@visactor/vchart
Version:
charts lib based @visactor/VGrammar
301 lines (284 loc) • 14.8 kB
JavaScript
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