UNPKG

@visactor/vchart

Version:

charts lib based @visactor/VGrammar

301 lines (284 loc) 14.8 kB
import { LayoutZIndex } from "./../../constant/layout"; import { Projection } from "./projection"; import { ComponentTypeEnum } from "../interface/type"; import { BaseComponent } from "../base/base-component"; import { eachSeries } from "../../util/model"; import { mergeSpec } from "@visactor/vutils-extension"; import { ChartEvent } from "../../constant/event"; import { PREFIX } from "../../constant/base"; import { SeriesTypeEnum } from "../../series/interface/type"; import { Zoomable } from "../../interaction/zoom/zoomable"; import { isValid, mixin, isNil, Matrix, isEqual } from "@visactor/vutils"; import { DEFAULT_MAP_LOOK_UP_KEY } from "../../data/transforms/map"; import { Factory } from "../../core/factory"; export function projectionName(key, id) { return `${PREFIX}_${id}_${key}`; } export class GeoCoordinate extends BaseComponent { constructor() { super(...arguments), this.type = ComponentTypeEnum.geoCoordinate, this.name = ComponentTypeEnum.geoCoordinate, this.layoutType = "none", this.layoutZIndex = LayoutZIndex.Mark, this._projectionSpec = { name: projectionName(this.type, this.id), type: "mercator" }, this._actualScale = 1, this._initialScale = 1, this.effect = { scaleUpdate: () => { this.coordinateHelper(); } }, this._handleChartZoom = (params, event) => { var _a, _b, _c, _d, _e, _f; let scale = params.zoomDelta; const _lastActualScale = this._actualScale; return this._actualScale *= scale, this._actualScale < (null === (_a = this._spec.zoomLimit) || void 0 === _a ? void 0 : _a.min) ? (this._actualScale = null === (_b = this._spec.zoomLimit) || void 0 === _b ? void 0 : _b.min, scale = (null === (_c = this._spec.zoomLimit) || void 0 === _c ? void 0 : _c.min) / _lastActualScale) : this._actualScale > (null === (_d = this._spec.zoomLimit) || void 0 === _d ? void 0 : _d.max) && (this._actualScale = null === (_e = this._spec.zoomLimit) || void 0 === _e ? void 0 : _e.max, scale = (null === (_f = this._spec.zoomLimit) || void 0 === _f ? void 0 : _f.max) / _lastActualScale), this.zoom(scale, [ params.zoomX, params.zoomY ]), { scale: scale, totalScale: this._actualScale }; }, this.pan = (delta = [ 0, 0 ]) => { var _a, _b, _c; const t = null !== (_b = null === (_a = this._projection) || void 0 === _a ? void 0 : _a.translate()) && void 0 !== _b ? _b : [ 0, 0 ]; let t_x = t[0], t_y = t[1]; t_x += delta[0], t_y += delta[1], null === (_c = this._projection) || void 0 === _c || _c.translate([ t_x, t_y ]); }; } get longitudeField() { return this._longitudeField; } get latitudeField() { return this._latitudeField; } get projectionSpec() { return this._projectionSpec; } setProjection(projectionSpec) { this._projectionSpec = Object.assign(Object.assign({}, projectionSpec), { name: this._projectionSpec.name }); } getZoom() { return this._actualScale; } static getSpecInfo(chartSpec) { if (isNil(chartSpec)) return null; const specInfos = []; return chartSpec.region.forEach(((r, i) => { if ("geo" === r.coordinate) { const spec = Object.assign(Object.assign({}, r), { padding: 0 }); specInfos.push({ spec: spec, regionIndex: i, type: ComponentTypeEnum.geoCoordinate, specInfoPath: [ "component", "geoCoordinate", i ] }); } })), specInfos; } setAttrFromSpec() { var _a, _b, _c; super.setAttrFromSpec(), this._spec.roam && this.initZoomable(this.event, this._option.mode), this._projectionSpec = mergeSpec(this._projectionSpec, this._spec.projection), this._projectionSpec.zoom > (null === (_a = this._spec.zoomLimit) || void 0 === _a ? void 0 : _a.max) && (this._projectionSpec.zoom = this._spec.zoomLimit.max), this._projectionSpec.zoom < (null === (_b = this._spec.zoomLimit) || void 0 === _b ? void 0 : _b.min) && (this._projectionSpec.zoom = this._spec.zoomLimit.min), this._actualScale = null !== (_c = this._projectionSpec.zoom) && void 0 !== _c ? _c : 1, this._initialScale = this._actualScale, this._longitudeField = this._spec.longitudeField, this._latitudeField = this._spec.latitudeField; } created() { super.created(), this._regions = this._option.getRegionsInIndex([ this._option.regionIndex ]), this.initProjection(), this.coordinateHelper(), this.initEvent(), this._initCenterCache(); } dispatchZoom(zoomDelta, center) { const scaleCenter = center || { x: this.getLayoutStartPoint().x + this.getLayoutRect().width / 2, y: this.getLayoutStartPoint().y + this.getLayoutRect().height / 2 }, {scale: scale, totalScale: totalScale} = this._handleChartZoom({ zoomDelta: zoomDelta, zoomX: scaleCenter.x, zoomY: scaleCenter.y }); 1 !== scale && this.event.emit("zoom", { scale: scale, scaleCenter: scaleCenter, totalScale: totalScale, model: this }); } initEvent() { this.event.on(ChartEvent.scaleUpdate, { filter: ({model: model}) => (null == model ? void 0 : model.id) === this.id }, this.effect.scaleUpdate.bind(this)); const {roam: roam} = this._spec; roam && (this.initZoomEventOfRegions(this._regions, null, this._handleChartZoom), this.initDragEventOfRegions(this._regions, roam.blank ? null : () => !0, this.pan), this._regions.forEach((r => { r.getSeries().forEach((s => { s.event.on("zoom", (e => (s.handleZoom(e), !0))), s.event.on("panmove", (e => (s.handlePan(e), !0))); })); }))); } initProjection() { var _a; this._projection = new Projection(this._projectionSpec), null !== this._projection.projection || null === (_a = this._option) || void 0 === _a || _a.onError("unsupported projection type!"); } coordinateHelper() { const helper = { longitudeField: this._longitudeField, latitudeField: this._latitudeField, dataToPosition: this.dataToPosition.bind(this), dataToLongitude: this.dataToLongitude.bind(this), dataToLatitude: this.dataToLatitude.bind(this), shape: this.shape.bind(this), getCoordinateId: () => this.id }; this._regions.forEach((r => { r.getSeries().forEach((s => { s.type === SeriesTypeEnum.map || s.type === SeriesTypeEnum.pictogram ? s.setCoordinateHelper(helper) : (s.setXAxisHelper(Object.assign(Object.assign({}, helper), { isContinuous: !0, dataToPosition: (values, option) => { var _a; let value = values[0]; if (isNil(value) && (null == option ? void 0 : option.datum)) { const nameFieldValue = option.datum[s.getDimensionField()[0]]; value = null === (_a = this._centerCache.get(nameFieldValue)) || void 0 === _a ? void 0 : _a.x; } return this.dataToLongitude(value); }, valueToPosition: (value, option) => { var _a; if (isNil(value) && (null == option ? void 0 : option.datum)) { const nameFieldValue = option.datum[s.getDimensionField()[0]]; value = null === (_a = this._centerCache.get(nameFieldValue)) || void 0 === _a ? void 0 : _a.x; } return this.dataToLongitude(value); }, getFields: () => [ this._longitudeField ], getAxisType: () => this.type, getAxisId: () => this.id, isInverse: () => !1 })), s.setYAxisHelper(Object.assign(Object.assign({}, helper), { isContinuous: !0, dataToPosition: (values, option) => { var _a; let value = values[0]; if (isNil(value) && (null == option ? void 0 : option.datum)) { const nameFieldValue = option.datum[s.getDimensionField()[0]]; value = null === (_a = this._centerCache.get(nameFieldValue)) || void 0 === _a ? void 0 : _a.y; } return this.dataToLatitude(value); }, valueToPosition: (value, option) => { var _a; if (isNil(value) && (null == option ? void 0 : option.datum)) { const nameFieldValue = option.datum[s.getDimensionField()[0]]; value = null === (_a = this._centerCache.get(nameFieldValue)) || void 0 === _a ? void 0 : _a.y; } return this.dataToLatitude(value); }, getFields: () => [ this._latitudeField ], getAxisType: () => this.type, getAxisId: () => this.id, isInverse: () => !1 }))); })); })); } onLayoutEnd() { this.setLayoutRect(this._regions[0].getLayoutRect()), this.setLayoutStartPosition(this._regions[0].getLayoutStartPoint()); const {width: width, height: height} = this.getLayoutRect(), {translate: translate, scale: scale, center: center} = this.evaluateProjection([ 0, 0 ], [ width, height ]); translate && this._projection.translate(translate), scale && this._projection.scale(scale), center && this._projection.center(center), eachSeries(this._regions, (s => { var _a; if (s.type === SeriesTypeEnum.map || s.type === SeriesTypeEnum.pictogram) { null === (_a = s.areaPath) || void 0 === _a || _a.clear(); const pathGroup = s.getRootMark().getProduct(); pathGroup && pathGroup.attribute.postMatrix && pathGroup.setAttributes({ postMatrix: new Matrix }); } })), this._actualScale = this._initialScale, super.onLayoutEnd(); } collectFeatures() { const features = []; return this._regions.forEach((r => { r.getSeries().forEach((s => { var _a, _b; s.type !== SeriesTypeEnum.map && s.type !== SeriesTypeEnum.pictogram || features.push(...null !== (_b = null === (_a = s.getMapViewData()) || void 0 === _a ? void 0 : _a.latestData) && void 0 !== _b ? _b : []); })); })), features; } dataToPosition(values = []) { var _a; const point = null === (_a = this._projection) || void 0 === _a ? void 0 : _a.project([ values[0], values[1] ]); return { x: null == point ? void 0 : point[0], y: null == point ? void 0 : point[1] }; } dataToLatitude(lat) { var _a; const point = null === (_a = this._projection) || void 0 === _a ? void 0 : _a.project([ 0, lat ]); return null == point ? void 0 : point[1]; } dataToLongitude(lon) { var _a; const point = null === (_a = this._projection) || void 0 === _a ? void 0 : _a.project([ lon, 0 ]); return null == point ? void 0 : point[0]; } zoom(p, anchor = [ 0, 0 ]) { var _a, _b, _c, _d, _e, _f; let s = null !== (_b = null === (_a = this._projection) || void 0 === _a ? void 0 : _a.scale()) && void 0 !== _b ? _b : 0; const t = null !== (_d = null === (_c = this._projection) || void 0 === _c ? void 0 : _c.translate()) && void 0 !== _d ? _d : [ 0, 0 ]; let t_x = t[0], t_y = t[1]; s *= p, t_x -= (anchor[0] - t_x) * (p - 1), t_y -= (anchor[1] - t_y) * (p - 1), null === (_e = this._projection) || void 0 === _e || _e.scale(s), null === (_f = this._projection) || void 0 === _f || _f.translate([ t_x, t_y ]); } shape(datum) { return this._projection.shape(datum); } invert(point) { return this._projection.invert(point); } evaluateProjection(start, size) { var _a; const evaluated = this._projection.evaluate(start, size, this.collectFeatures()); let translate = evaluated.translate(); const scale = evaluated.scale() * this._initialScale, center = null !== (_a = this._projectionSpec.center) && void 0 !== _a ? _a : evaluated.invert([ size[0] / 2, size[1] / 2 ]); return center && (translate = [ size[0] / 2, size[1] / 2 ]), { translate: translate, scale: scale, center: center }; } _initCenterCache() { this._centerCache || (this._centerCache = new Map), this._regions.forEach((r => { r.getSeries().forEach((s => { var _a, _b; if ("map" === s.type) { (null !== (_b = null === (_a = s.getMapViewData()) || void 0 === _a ? void 0 : _a.latestData) && void 0 !== _b ? _b : []).forEach(((feature = {}) => { const key = feature[s.getDimensionField()[0]] || feature[DEFAULT_MAP_LOOK_UP_KEY], center = s.getDatumCenter(feature); key && isValid(center) && this._centerCache.set(key, { x: center[0], y: center[1] }); })); } })); })); } _compareSpec(spec, prevSpec) { const result = super._compareSpec(spec, prevSpec); return result.reMake || (result.reMake = [ "roam", "longitudeField", "latitudeField", "projection", "zoomLimit" ].some((k => !isEqual(null == prevSpec ? void 0 : prevSpec[k], spec[k])))), result; } release() { super.release(), this._centerCache && this._centerCache.clear(), this._centerCache = null; } } GeoCoordinate.type = ComponentTypeEnum.geoCoordinate, mixin(GeoCoordinate, Zoomable); export const registerGeoCoordinate = () => { Factory.registerComponent(GeoCoordinate.type, GeoCoordinate); }; //# sourceMappingURL=geo-coordinate.js.map