blob: 349dbb72817c4bc4e1d8b6c05e382a2af4be8750 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import {parseSVG, makeViewBoxTransform} from 'zrender/src/tool/parseSVG';
import Group from 'zrender/src/graphic/Group';
import Rect from 'zrender/src/graphic/shape/Rect';
import {assert, createHashMap, HashMap} from 'zrender/src/core/util';
import BoundingRect from 'zrender/src/core/BoundingRect';
import {makeInner} from '../../util/model';
import { SVGMapRecord } from './mapDataStorage';
type MapRecordInner = {
originRoot: Group;
boundingRect: BoundingRect;
// key: hostKey, value: root
rootMap: HashMap<Group>;
originRootHostKey: string;
};
const inner = makeInner<MapRecordInner, SVGMapRecord>();
export default {
load(mapName: string, mapRecord: SVGMapRecord): ReturnType<typeof buildGraphic> {
const originRoot = inner(mapRecord).originRoot;
if (originRoot) {
return {
root: originRoot,
boundingRect: inner(mapRecord).boundingRect
};
}
const graphic = buildGraphic(mapRecord);
inner(mapRecord).originRoot = graphic.root;
inner(mapRecord).boundingRect = graphic.boundingRect;
return graphic;
},
makeGraphic(mapName: string, mapRecord: SVGMapRecord, hostKey: string): Group {
// For performance consideration (in large SVG), graphic only maked
// when necessary and reuse them according to hostKey.
const field = inner(mapRecord);
const rootMap = field.rootMap || (field.rootMap = createHashMap());
let root = rootMap.get(hostKey);
if (root) {
return root;
}
const originRoot = field.originRoot;
const boundingRect = field.boundingRect;
// For performance, if originRoot is not used by a view,
// assign it to a view, but not reproduce graphic elements.
if (!field.originRootHostKey) {
field.originRootHostKey = hostKey;
root = originRoot;
}
else {
root = buildGraphic(mapRecord, boundingRect).root;
}
return rootMap.set(hostKey, root);
},
removeGraphic(mapName: string, mapRecord: SVGMapRecord, hostKey: string): void {
const field = inner(mapRecord);
const rootMap = field.rootMap;
rootMap && rootMap.removeKey(hostKey);
if (hostKey === field.originRootHostKey) {
field.originRootHostKey = null;
}
}
};
function buildGraphic(
mapRecord: SVGMapRecord, boundingRect?: BoundingRect
): {
root: Group;
boundingRect: BoundingRect;
} {
const svgXML = mapRecord.svgXML;
let result;
let root;
try {
result = svgXML && parseSVG(svgXML, {
ignoreViewBox: true,
ignoreRootClip: true
}) || {};
root = result.root;
assert(root != null);
}
catch (e) {
throw new Error('Invalid svg format\n' + e.message);
}
const svgWidth = result.width;
const svgHeight = result.height;
const viewBoxRect = result.viewBoxRect;
if (!boundingRect) {
boundingRect = (svgWidth == null || svgHeight == null)
// If svg width / height not specified, calculate
// bounding rect as the width / height
? root.getBoundingRect()
: new BoundingRect(0, 0, 0, 0);
if (svgWidth != null) {
boundingRect.width = svgWidth;
}
if (svgHeight != null) {
boundingRect.height = svgHeight;
}
}
if (viewBoxRect) {
const viewBoxTransform = makeViewBoxTransform(viewBoxRect, boundingRect.width, boundingRect.height);
const elRoot = root;
root = new Group();
root.add(elRoot);
elRoot.scaleX = elRoot.scaleY = viewBoxTransform.scale;
elRoot.x = viewBoxTransform.x;
elRoot.y = viewBoxTransform.y;
}
root.setClipPath(new Rect({
shape: boundingRect.plain()
}));
return {
root: root,
boundingRect: boundingRect
};
}