blob: f65553ca024f031edb47b6fdf3107730cb957f9e [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 * as zrUtil from 'zrender/src/core/util';
import * as modelUtil from '../../util/model';
import ComponentModel from '../../model/Component';
import Model from '../../model/Model';
import geoCreator from './geoCreator';
import Geo from './Geo';
import {
ComponentOption,
BoxLayoutOptionMixin,
ItemStyleOption,
ZRColor,
LabelOption,
DisplayState,
RoamOptionMixin,
AnimationOptionMixin,
StatesOptionMixin,
Dictionary,
CommonTooltipOption
} from '../../util/types';
import { NameMap } from './geoTypes';
import GlobalModel from '../../model/Global';
import geoSourceManager from './geoSourceManager';
export interface GeoItemStyleOption extends ItemStyleOption {
areaColor?: ZRColor;
};
interface GeoLabelOption extends LabelOption {
formatter?: string | ((params: GeoLabelFormatterDataParams) => string);
}
export interface GeoStateOption {
itemStyle?: GeoItemStyleOption
// FIXME:TS formatter?
label?: GeoLabelOption
}
interface GeoLabelFormatterDataParams {
name: string;
status: DisplayState;
}
export interface RegoinOption extends GeoStateOption, StatesOptionMixin<GeoStateOption> {
name?: string
selected?: boolean
tooltip?: CommonTooltipOption<GeoTooltipFormatterParams>
}
export interface GeoTooltipFormatterParams {
componentType: 'geo'
geoIndex: number
name: string
$vars: ['name']
}
export interface GeoCommonOptionMixin extends RoamOptionMixin {
// Map name
map: string;
// Aspect is width / height. Inited to be geoJson bbox aspect
// This parameter is used for scale this aspect
aspectScale?: number;
///// Layout with center and size
// If you wan't to put map in a fixed size box with right aspect ratio
// This two properties may more conveninet
// Like: `40` or `'50%'`.
layoutCenter?: (number | string)[];
// Like: `40` or `'50%'`.
layoutSize?: number | string;
// Define left-top, right-bottom coords to control view
// For example, [ [180, 90], [-180, -90] ]
// higher priority than center and zoom
boundingCoords?: number[][];
nameMap?: NameMap;
nameProperty?: string;
}
export interface GeoOption extends
ComponentOption,
BoxLayoutOptionMixin,
// For lens animation on geo.
AnimationOptionMixin,
GeoCommonOptionMixin,
StatesOptionMixin<GeoStateOption>, GeoStateOption {
mainType?: 'geo';
show?: boolean;
silent?: boolean;
regions?: RegoinOption[];
stateAnimation?: AnimationOptionMixin
selectedMode?: 'single' | 'multiple' | boolean
selectedMap?: Dictionary<boolean>
tooltip?: CommonTooltipOption<GeoTooltipFormatterParams>
}
class GeoModel extends ComponentModel<GeoOption> {
static type = 'geo';
readonly type = GeoModel.type;
coordinateSystem: Geo;
static layoutMode = 'box' as const;
private _optionModelMap: zrUtil.HashMap<Model<RegoinOption>>;
static defaultOption: GeoOption = {
zlevel: 0,
z: 0,
show: true,
left: 'center',
top: 'center',
// Default value:
// for geoSVG source: 1,
// for geoJSON source: 0.75.
aspectScale: null,
///// Layout with center and size
// If you wan't to put map in a fixed size box with right aspect ratio
// This two properties may more conveninet
// layoutCenter: [50%, 50%]
// layoutSize: 100
silent: false,
// Map type
map: '',
// Define left-top, right-bottom coords to control view
// For example, [ [180, 90], [-180, -90] ]
boundingCoords: null,
// Default on center of map
center: null,
zoom: 1,
scaleLimit: null,
// selectedMode: false
label: {
show: false,
color: '#000'
},
itemStyle: {
borderWidth: 0.5,
borderColor: '#444'
// Default color:
// + geoJSON: #eee
// + geoSVG: null (use SVG original `fill`)
// color: '#eee'
},
emphasis: {
label: {
show: true,
color: 'rgb(100,0,0)'
},
itemStyle: {
color: 'rgba(255,215,0,0.8)'
}
},
select: {
label: {
show: true,
color: 'rgb(100,0,0)'
},
itemStyle: {
color: 'rgba(255,215,0,0.8)'
}
},
regions: []
// tooltip: {
// show: false
// }
};
init(option: GeoOption, parentModel: Model, ecModel: GlobalModel): void {
const source = geoSourceManager.getGeoResource(option.map);
if (source && source.type === 'geoJSON') {
const itemStyle = option.itemStyle = option.itemStyle || {};
if (!('color' in itemStyle)) {
itemStyle.color = '#eee';
}
}
this.mergeDefaultAndTheme(option, ecModel);
// Default label emphasis `show`
modelUtil.defaultEmphasis(option, 'label', ['show']);
}
optionUpdated(): void {
const option = this.option;
option.regions = geoCreator.getFilledRegions(
option.regions, option.map, option.nameMap, option.nameProperty
);
const selectedMap: Dictionary<boolean> = {};
this._optionModelMap = zrUtil.reduce(option.regions || [], (optionModelMap, regionOpt) => {
const regionName = regionOpt.name;
if (regionName) {
optionModelMap.set(regionName, new Model(regionOpt, this, this.ecModel));
if (regionOpt.selected) {
selectedMap[regionName] = true;
}
}
return optionModelMap;
}, zrUtil.createHashMap());
if (!option.selectedMap) {
option.selectedMap = selectedMap;
}
}
/**
* Get model of region.
*/
getRegionModel(name: string): Model<RegoinOption> {
return this._optionModelMap.get(name) || new Model(null, this, this.ecModel);
}
/**
* Format label
* @param name Region name
*/
getFormattedLabel(name: string, status?: DisplayState) {
const regionModel = this.getRegionModel(name);
const formatter = status === 'normal'
? regionModel.get(['label', 'formatter'])
: regionModel.get(['emphasis', 'label', 'formatter']);
const params = {
name: name
} as GeoLabelFormatterDataParams;
if (typeof formatter === 'function') {
params.status = status;
return formatter(params);
}
else if (typeof formatter === 'string') {
return formatter.replace('{a}', name != null ? name : '');
}
}
setZoom(zoom: number): void {
this.option.zoom = zoom;
}
setCenter(center: number[]): void {
this.option.center = center;
}
// PENGING If selectedMode is null ?
select(name?: string): void {
const option = this.option;
const selectedMode = option.selectedMode;
if (!selectedMode) {
return;
}
if (selectedMode !== 'multiple') {
option.selectedMap = null;
}
const selectedMap = option.selectedMap || (option.selectedMap = {});
selectedMap[name] = true;
}
unSelect(name?: string): void {
const selectedMap = this.option.selectedMap;
if (selectedMap) {
selectedMap[name] = false;
}
}
toggleSelected(name?: string): void {
this[this.isSelected(name) ? 'unSelect' : 'select'](name);
}
isSelected(name?: string): boolean {
const selectedMap = this.option.selectedMap;
return !!(selectedMap && selectedMap[name]);
}
}
export default GeoModel;