123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- /*
- * 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.
- */
- var zrUtil = require("zrender/lib/core/util");
- var RoamController = require("./RoamController");
- var roamHelper = require("../../component/helper/roamHelper");
- var _cursorHelper = require("../../component/helper/cursorHelper");
- var onIrrelevantElement = _cursorHelper.onIrrelevantElement;
- var graphic = require("../../util/graphic");
- var geoSourceManager = require("../../coord/geo/geoSourceManager");
- var _component = require("../../util/component");
- var getUID = _component.getUID;
- var Transformable = require("zrender/lib/mixin/Transformable");
- /*
- * 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.
- */
- function getFixedItemStyle(model) {
- var itemStyle = model.getItemStyle();
- var areaColor = model.get('areaColor'); // If user want the color not to be changed when hover,
- // they should both set areaColor and color to be null.
- if (areaColor != null) {
- itemStyle.fill = areaColor;
- }
- return itemStyle;
- }
- function updateMapSelectHandler(mapDraw, mapOrGeoModel, regionsGroup, api, fromView) {
- regionsGroup.off('click');
- regionsGroup.off('mousedown');
- if (mapOrGeoModel.get('selectedMode')) {
- regionsGroup.on('mousedown', function () {
- mapDraw._mouseDownFlag = true;
- });
- regionsGroup.on('click', function (e) {
- if (!mapDraw._mouseDownFlag) {
- return;
- }
- mapDraw._mouseDownFlag = false;
- var el = e.target;
- while (!el.__regions) {
- el = el.parent;
- }
- if (!el) {
- return;
- }
- var action = {
- type: (mapOrGeoModel.mainType === 'geo' ? 'geo' : 'map') + 'ToggleSelect',
- batch: zrUtil.map(el.__regions, function (region) {
- return {
- name: region.name,
- from: fromView.uid
- };
- })
- };
- action[mapOrGeoModel.mainType + 'Id'] = mapOrGeoModel.id;
- api.dispatchAction(action);
- updateMapSelected(mapOrGeoModel, regionsGroup);
- });
- }
- }
- function updateMapSelected(mapOrGeoModel, regionsGroup) {
- // FIXME
- regionsGroup.eachChild(function (otherRegionEl) {
- zrUtil.each(otherRegionEl.__regions, function (region) {
- otherRegionEl.trigger(mapOrGeoModel.isSelected(region.name) ? 'emphasis' : 'normal');
- });
- });
- }
- /**
- * @alias module:echarts/component/helper/MapDraw
- * @param {module:echarts/ExtensionAPI} api
- * @param {boolean} updateGroup
- */
- function MapDraw(api, updateGroup) {
- var group = new graphic.Group();
- /**
- * @type {string}
- * @private
- */
- this.uid = getUID('ec_map_draw');
- /**
- * @type {module:echarts/component/helper/RoamController}
- * @private
- */
- this._controller = new RoamController(api.getZr());
- /**
- * @type {Object} {target, zoom, zoomLimit}
- * @private
- */
- this._controllerHost = {
- target: updateGroup ? group : null
- };
- /**
- * @type {module:zrender/container/Group}
- * @readOnly
- */
- this.group = group;
- /**
- * @type {boolean}
- * @private
- */
- this._updateGroup = updateGroup;
- /**
- * This flag is used to make sure that only one among
- * `pan`, `zoom`, `click` can occurs, otherwise 'selected'
- * action may be triggered when `pan`, which is unexpected.
- * @type {booelan}
- */
- this._mouseDownFlag;
- /**
- * @type {string}
- */
- this._mapName;
- /**
- * @type {boolean}
- */
- this._initialized;
- /**
- * @type {module:zrender/container/Group}
- */
- group.add(this._regionsGroup = new graphic.Group());
- /**
- * @type {module:zrender/container/Group}
- */
- group.add(this._backgroundGroup = new graphic.Group());
- }
- MapDraw.prototype = {
- constructor: MapDraw,
- draw: function (mapOrGeoModel, ecModel, api, fromView, payload) {
- var isGeo = mapOrGeoModel.mainType === 'geo'; // Map series has data. GEO model that controlled by map series
- // will be assigned with map data. Other GEO model has no data.
- var data = mapOrGeoModel.getData && mapOrGeoModel.getData();
- isGeo && ecModel.eachComponent({
- mainType: 'series',
- subType: 'map'
- }, function (mapSeries) {
- if (!data && mapSeries.getHostGeoModel() === mapOrGeoModel) {
- data = mapSeries.getData();
- }
- });
- var geo = mapOrGeoModel.coordinateSystem;
- this._updateBackground(geo);
- var regionsGroup = this._regionsGroup;
- var group = this.group;
- var transformInfo = geo.getTransformInfo(); // No animation when first draw or in action
- var isFirstDraw = !regionsGroup.childAt(0) || payload;
- var targetScale;
- if (isFirstDraw) {
- group.transform = transformInfo.roamTransform;
- group.decomposeTransform();
- group.dirty();
- } else {
- var target = new Transformable();
- target.transform = transformInfo.roamTransform;
- target.decomposeTransform();
- var props = {
- scale: target.scale,
- position: target.position
- };
- targetScale = target.scale;
- graphic.updateProps(group, props, mapOrGeoModel);
- }
- var scale = transformInfo.rawScale;
- var position = transformInfo.rawPosition;
- regionsGroup.removeAll();
- var itemStyleAccessPath = ['itemStyle'];
- var hoverItemStyleAccessPath = ['emphasis', 'itemStyle'];
- var labelAccessPath = ['label'];
- var hoverLabelAccessPath = ['emphasis', 'label'];
- var nameMap = zrUtil.createHashMap();
- zrUtil.each(geo.regions, function (region) {
- // Consider in GeoJson properties.name may be duplicated, for example,
- // there is multiple region named "United Kindom" or "France" (so many
- // colonies). And it is not appropriate to merge them in geo, which
- // will make them share the same label and bring trouble in label
- // location calculation.
- var regionGroup = nameMap.get(region.name) || nameMap.set(region.name, new graphic.Group());
- var compoundPath = new graphic.CompoundPath({
- segmentIgnoreThreshold: 1,
- shape: {
- paths: []
- }
- });
- regionGroup.add(compoundPath);
- var regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel;
- var itemStyleModel = regionModel.getModel(itemStyleAccessPath);
- var hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath);
- var itemStyle = getFixedItemStyle(itemStyleModel);
- var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel);
- var labelModel = regionModel.getModel(labelAccessPath);
- var hoverLabelModel = regionModel.getModel(hoverLabelAccessPath);
- var dataIdx; // Use the itemStyle in data if has data
- if (data) {
- dataIdx = data.indexOfName(region.name); // Only visual color of each item will be used. It can be encoded by dataRange
- // But visual color of series is used in symbol drawing
- //
- // Visual color for each series is for the symbol draw
- var visualColor = data.getItemVisual(dataIdx, 'color', true);
- if (visualColor) {
- itemStyle.fill = visualColor;
- }
- }
- var transformPoint = function (point) {
- return [point[0] * scale[0] + position[0], point[1] * scale[1] + position[1]];
- };
- zrUtil.each(region.geometries, function (geometry) {
- if (geometry.type !== 'polygon') {
- return;
- }
- var points = [];
- for (var i = 0; i < geometry.exterior.length; ++i) {
- points.push(transformPoint(geometry.exterior[i]));
- }
- compoundPath.shape.paths.push(new graphic.Polygon({
- segmentIgnoreThreshold: 1,
- shape: {
- points: points
- }
- }));
- for (var i = 0; i < (geometry.interiors ? geometry.interiors.length : 0); ++i) {
- var interior = geometry.interiors[i];
- var points = [];
- for (var j = 0; j < interior.length; ++j) {
- points.push(transformPoint(interior[j]));
- }
- compoundPath.shape.paths.push(new graphic.Polygon({
- segmentIgnoreThreshold: 1,
- shape: {
- points: points
- }
- }));
- }
- });
- compoundPath.setStyle(itemStyle);
- compoundPath.style.strokeNoScale = true;
- compoundPath.culling = true; // Label
- var showLabel = labelModel.get('show');
- var hoverShowLabel = hoverLabelModel.get('show');
- var isDataNaN = data && isNaN(data.get(data.mapDimension('value'), dataIdx));
- var itemLayout = data && data.getItemLayout(dataIdx); // In the following cases label will be drawn
- // 1. In map series and data value is NaN
- // 2. In geo component
- // 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout
- if (isGeo || isDataNaN && (showLabel || hoverShowLabel) || itemLayout && itemLayout.showLabel) {
- var query = !isGeo ? dataIdx : region.name;
- var labelFetcher; // Consider dataIdx not found.
- if (!data || dataIdx >= 0) {
- labelFetcher = mapOrGeoModel;
- }
- var textEl = new graphic.Text({
- position: transformPoint(region.center.slice()),
- // FIXME
- // label rotation is not support yet in geo or regions of series-map
- // that has no data. The rotation will be effected by this `scale`.
- // So needed to change to RectText?
- scale: [1 / group.scale[0], 1 / group.scale[1]],
- z2: 10,
- silent: true
- });
- graphic.setLabelStyle(textEl.style, textEl.hoverStyle = {}, labelModel, hoverLabelModel, {
- labelFetcher: labelFetcher,
- labelDataIndex: query,
- defaultText: region.name,
- useInsideStyle: false
- }, {
- textAlign: 'center',
- textVerticalAlign: 'middle'
- });
- if (!isFirstDraw) {
- // Text animation
- var textScale = [1 / targetScale[0], 1 / targetScale[1]];
- graphic.updateProps(textEl, {
- scale: textScale
- }, mapOrGeoModel);
- }
- regionGroup.add(textEl);
- } // setItemGraphicEl, setHoverStyle after all polygons and labels
- // are added to the rigionGroup
- if (data) {
- data.setItemGraphicEl(dataIdx, regionGroup);
- } else {
- var regionModel = mapOrGeoModel.getRegionModel(region.name); // Package custom mouse event for geo component
- compoundPath.eventData = {
- componentType: 'geo',
- componentIndex: mapOrGeoModel.componentIndex,
- geoIndex: mapOrGeoModel.componentIndex,
- name: region.name,
- region: regionModel && regionModel.option || {}
- };
- }
- var groupRegions = regionGroup.__regions || (regionGroup.__regions = []);
- groupRegions.push(region);
- regionGroup.highDownSilentOnTouch = !!mapOrGeoModel.get('selectedMode');
- graphic.setHoverStyle(regionGroup, hoverItemStyle);
- regionsGroup.add(regionGroup);
- });
- this._updateController(mapOrGeoModel, ecModel, api);
- updateMapSelectHandler(this, mapOrGeoModel, regionsGroup, api, fromView);
- updateMapSelected(mapOrGeoModel, regionsGroup);
- },
- remove: function () {
- this._regionsGroup.removeAll();
- this._backgroundGroup.removeAll();
- this._controller.dispose();
- this._mapName && geoSourceManager.removeGraphic(this._mapName, this.uid);
- this._mapName = null;
- this._controllerHost = {};
- },
- _updateBackground: function (geo) {
- var mapName = geo.map;
- if (this._mapName !== mapName) {
- zrUtil.each(geoSourceManager.makeGraphic(mapName, this.uid), function (root) {
- this._backgroundGroup.add(root);
- }, this);
- }
- this._mapName = mapName;
- },
- _updateController: function (mapOrGeoModel, ecModel, api) {
- var geo = mapOrGeoModel.coordinateSystem;
- var controller = this._controller;
- var controllerHost = this._controllerHost;
- controllerHost.zoomLimit = mapOrGeoModel.get('scaleLimit');
- controllerHost.zoom = geo.getZoom(); // roamType is will be set default true if it is null
- controller.enable(mapOrGeoModel.get('roam') || false);
- var mainType = mapOrGeoModel.mainType;
- function makeActionBase() {
- var action = {
- type: 'geoRoam',
- componentType: mainType
- };
- action[mainType + 'Id'] = mapOrGeoModel.id;
- return action;
- }
- controller.off('pan').on('pan', function (e) {
- this._mouseDownFlag = false;
- roamHelper.updateViewOnPan(controllerHost, e.dx, e.dy);
- api.dispatchAction(zrUtil.extend(makeActionBase(), {
- dx: e.dx,
- dy: e.dy
- }));
- }, this);
- controller.off('zoom').on('zoom', function (e) {
- this._mouseDownFlag = false;
- roamHelper.updateViewOnZoom(controllerHost, e.scale, e.originX, e.originY);
- api.dispatchAction(zrUtil.extend(makeActionBase(), {
- zoom: e.scale,
- originX: e.originX,
- originY: e.originY
- }));
- if (this._updateGroup) {
- var scale = this.group.scale;
- this._regionsGroup.traverse(function (el) {
- if (el.type === 'text') {
- el.attr('scale', [1 / scale[0], 1 / scale[1]]);
- }
- });
- }
- }, this);
- controller.setPointerChecker(function (e, x, y) {
- return geo.getViewRectAfterRoam().contain(x, y) && !onIrrelevantElement(e, api, mapOrGeoModel);
- });
- }
- };
- var _default = MapDraw;
- module.exports = _default;
|