前端初始化

This commit is contained in:
“hsc”
2026-08-21 15:36:24 +08:00
commit e4d8ecde13
14411 changed files with 2275932 additions and 0 deletions
+277
View File
@@ -0,0 +1,277 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { each, map } from 'zrender/lib/core/util.js';
import { linearMap } from '../util/number.js';
import { createAxisTicks, createAxisLabels, calculateCategoryInterval, AxisTickLabelComputingKind, createAxisLabelsComputingContext } from './axisTickLabelBuilder.js';
import { isOrdinalScale } from '../scale/helper.js';
import { calcBandWidth } from './axisBand.js';
import { getTickValueOutermost } from './axisHelper.js';
var NORMALIZED_EXTENT = [0, 1];
/**
* Base class of Axis.
*
* Lifetime: recreate for each main process.
* [NOTICE]: Some caches is stored on the axis instance (e.g., `axisTickLabelBuilder.ts`, `scaleRawExtentInfo.ts`),
* which is based on this lifetime.
*/
var Axis = /** @class */function () {
function Axis(dim, scale, extent) {
// NOTICE: Must ensure `true` is only available on 'category' axis.
this.onBand = false;
// Make sure that `extent[0] > extent[1]` only if `inverse: true`.
// `inverse` can be inferred by `extent` unless `extent[0] === extent[1]`.
this.inverse = false;
this.dim = dim;
this.scale = scale;
this._extent = extent || [0, 0];
}
/**
* If axis extent contain given coord
*/
Axis.prototype.contain = function (coord) {
var extent = this._extent;
var min = Math.min(extent[0], extent[1]);
var max = Math.max(extent[0], extent[1]);
return coord >= min && coord <= max;
};
/**
* If axis extent contain given data
*/
Axis.prototype.containData = function (data) {
return this.scale.contain(this.scale.parse(data));
};
/**
* Get coord extent.
*/
Axis.prototype.getExtent = function () {
return this._extent.slice();
};
/**
* Set coord extent
*/
Axis.prototype.setExtent = function (start, end) {
var extent = this._extent;
extent[0] = start;
extent[1] = end;
};
/**
* Convert data to coord. Data is the rank if it has an ordinal scale
*/
Axis.prototype.dataToCoord = function (data, clamp) {
var scale = this.scale;
data = scale.normalize(scale.parse(data));
return linearMap(data, NORMALIZED_EXTENT, makeExtentWithBands(this), clamp);
};
/**
* Convert coord to data. Data is the rank if it has an ordinal scale
*/
Axis.prototype.coordToData = function (coord, clamp) {
var t = linearMap(coord, makeExtentWithBands(this), NORMALIZED_EXTENT, clamp);
return this.scale.scale(t);
};
/**
* Convert pixel point to data in axis
*/
Axis.prototype.pointToData = function (point, clamp) {
// Should be implemented in derived class if necessary.
return;
};
/**
* Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,
* `axis.getTicksCoords` considers `onBand`, which is used by
* `boundaryGap:true` of category axis and splitLine and splitArea.
* @param opt.tickModel default: axis.model.getModel('axisTick')
*/
Axis.prototype.getTicksCoords = function (opt) {
opt = opt || {};
var tickModel = opt.tickModel || this.getTickModel();
var result = createAxisTicks(this, tickModel, {
breakTicks: opt.breakTicks,
pruneByBreak: opt.pruneByBreak
});
var preTicksCoords = map(result.ticks, function (tick) {
return {
coord: this.dataToCoord(getTickValueOutermost(this.scale, tick)),
tick: tick
};
}, this);
var alignWithLabel = tickModel.get('alignWithLabel');
var onBandModified = fixOnBandTicksCoords(this, preTicksCoords, alignWithLabel);
return map(preTicksCoords, function (item) {
return {
coord: item.coord,
tickValue: item.tick.value,
onBand: onBandModified
};
});
};
Axis.prototype.getMinorTicksCoords = function () {
if (isOrdinalScale(this.scale)) {
// Category axis doesn't support minor ticks
return [];
}
var minorTickModel = this.model.getModel('minorTick');
var splitNumber = minorTickModel.get('splitNumber');
// Protection.
if (!(splitNumber > 0 && splitNumber < 100)) {
splitNumber = 5;
}
var minorTicks = this.scale.getMinorTicks(splitNumber);
var minorTicksCoords = map(minorTicks, function (minorTicksGroup) {
return map(minorTicksGroup, function (minorTick) {
return {
coord: this.dataToCoord(minorTick),
tickValue: minorTick
};
}, this);
}, this);
return minorTicksCoords;
};
Axis.prototype.getViewLabels = function (ctx) {
ctx = ctx || createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine);
return createAxisLabels(this, ctx).labels;
};
Axis.prototype.getLabelModel = function () {
return this.model.getModel('axisLabel');
};
/**
* Notice here we only get the default tick model. For splitLine
* or splitArea, we should pass the splitLineModel or splitAreaModel
* manually when calling `getTicksCoords`.
* In GL, this method may be overridden to:
* `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`
*/
Axis.prototype.getTickModel = function () {
return this.model.getModel('axisTick');
};
/**
* @deprecated Use `calcBandWidth` instead.
*/
Axis.prototype.getBandWidth = function () {
return calcBandWidth(this, {
min: 1
}).w;
// NOTICE: Do not add logic here. Implement everthing in `calcBandWidth`.
};
/**
* Only be called in category axis.
* Can be overridden, consider other axes like in 3D.
* @return Auto interval for category axis tick and label
*/
Axis.prototype.calculateCategoryInterval = function (ctx) {
ctx = ctx || createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine);
return calculateCategoryInterval(this, ctx);
};
return Axis;
}();
function makeExtentWithBands(axis) {
var extent = axis.getExtent();
if (axis.onBand) {
var size = extent[1] - extent[0];
var margin = size / axis.scale.count() / 2;
extent[0] += margin;
extent[1] -= margin;
}
return extent;
}
/**
* `axis.onBand: true` (i.e., `boundaryGap: true` in ec option) and `CategoryTickLabelSplitIntervalOption`
* affects `axisTick`/`axisLabel`/`splitLine`/`splitArea`.
*
* Currently, the visual result is best only when `axisTick/splitLine/splitArea.interval === 0`.
* The typical case is:
* |---|---|---| <= This is the input `preTicksCoords`
* 0 1 2 3 (having been added half band width by `makeExtentWithBands`).
* |---|---|---|---| <= This is the result.
* 0 1 2 3
*
* When `interval > 0`, the visual result may be odd for `axisLabel` and `customValues`, but acceptable
* for `axisTick` `splitLine` and `splitArea`:
* |---~---|---~---~---|---| <= This is the input `preTicksCoords`; `interval: 2; min: 1; max: 7`.
* ₁ ₂ 3 ₄ ₅ 6 ₇ Subscript numbers (`₀`, `₁`, `₃`) indicate axis labels are hidden
* (by default settings) due to off-interval.
* A tilde (`~`) indicates a tick ignored due to off-interval.
* |---~---|---~---~---|---~---| <= This is the result.
* ₁ ₂ 3 ₄ ₅ 6 ₇
*
* NOTE:
* - A inappropriate result may cause misleading (e.g., split 2 bars of a single data item when there
* are two bar series).
* - See also #11176 #11186 .
* PENDING:
* - The show/hide of `axisLabel` may be optimized when `interval > 1 and be an even number`,
* but that may introduce complex and still not perfect in odd number, and may not necessary if
* `axisTick: {show: false}` and `axisLabel` can auto hidden when overlapping.
*/
function fixOnBandTicksCoords(axis, preTicksCoords, alignWithLabel) {
var ticksLen = preTicksCoords.length;
if (!axis.onBand || alignWithLabel || !ticksLen) {
return false;
}
// Assume:
// - If `onBand: true`, `bandWidth` has been calculated by `ticksLen + 1` rather than `ticksLen`.
// - If `interval > 0`, some ticks may be ignored, but `ticksCoords` has always included boundary
// ticks of axis extent, and be `offInterval: true` if off-interval.
// - No need to consider breaks, since axis break is not supported in category axis.
var bandWidth = calcBandWidth(axis).w;
if (!bandWidth) {
return false;
}
each(preTicksCoords, function (ticksItem) {
ticksItem.coord -= bandWidth / 2;
});
var dataExtent = axis.scale.getExtent();
var oldLast = preTicksCoords[ticksLen - 1];
if (oldLast.tick.offInterval) {
preTicksCoords.pop();
}
preTicksCoords.push({
coord: oldLast.coord + bandWidth,
tick: {
value: dataExtent[1] + 1
}
});
return true;
}
export default Axis;
+44
View File
@@ -0,0 +1,44 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
export {};
+51
View File
@@ -0,0 +1,51 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
export function isCoordinateSystemType(coordSys, type) {
return coordSys.type === type;
}
export function isGeoLikeCoordSys(coordSys) {
var dimensions = coordSys.dimensions;
// Not use coordSys.type === 'geo' because coordSys maybe extended
return dimensions[0] === 'lng' && dimensions[1] === 'lat' && !!coordSys.getViewRect;
}
+615
View File
@@ -0,0 +1,615 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import BoundingRect, { boundingRectApplyTransform, boundingRectCalculateTransform, boundingRectContain, boundingRectCopy, boundingRectCreate } from 'zrender/lib/core/BoundingRect.js';
import Transformable, { copyTransform, transformableCreate, transformableGetLocalTransform } from 'zrender/lib/core/Transformable.js';
import { isPositionSizeOptionPercent, mathAbs, parsePercent } from '../util/number.js';
import { assert, each } from 'zrender/lib/core/util.js';
import { getViewOfComponentOrSeries } from '../core/ExtensionAPI.js';
import { decomposeTransform, payloadDisableAnimation, updateProps, WH, XY } from '../util/graphic.js';
import { invert as matrixInvert, mul as matrixMul, create as matrixCreate, copy as matrixCopy } from 'zrender/lib/core/matrix.js';
import { applyTransform as vectorApplyTransform, copy as vectorCopy, set as vectorSet } from 'zrender/lib/core/vector.js';
/**
* @tutorial [VIEW_COORD_SYS_ANIMATION]
*
* Some VIEW_COORD_SYS may need to support roaming animation, which may be required when the original
* inputs (such as `center/zoom/left/top/right/bottomwidth/height/etc.`) are changed via `setOption`.
* Roaming animation requires strict visual alignment between VIEW_COORD_SYS itself (consider "geo map")
* and its content (e.g., scatter series).
* A logically correct implementation is probably applying animation to VIEW_COORD_SYS's inputs and
* calculate VIEW_COORD_SYS's transformation and lay out its dependent series per frame via
* `dispatchAction`-ish pattern. But this approach require more mechanism to be introduced and careful
* refactoring.
* Instead, we currently still follow the conventional implementation - create animation separately on
* each element (typically via `graphic.updateProps`) . See VIEW_COORD_SYS_ANIMATION_PROPS_CONSTRAINT.
*
* [VIEW_COORD_SYS_ANIMATION_PROPS_CONSTRAINT]:
* The animation should only interpolate `x/y/scaleX/scaleY`, thereby ensuring visual alignment, even
* though `MapDraw` applies animations only on a "VIEW_COORD_SYS_TRANS_ROAM" but scatter series applies
* animation on a "VIEW_COORD_SYS_TRANS_OVERALL".
* But this constraint must always be respected by all relevant components and series.
*
* [VIEW_COORD_SYS_ANIMATION_INTERRUPTION]:
* The animation should be able to be interrupted, such as when users roam it by mouse or touch.
* When interrupted, `center` and `zoom` must be synchronized back to the VIEW_COORD_SYS and host models
* (e.g., geo components or map series). Otherwise, a next `setOption` can cause unexpected result due to
* the outdated `center` and `zoom`.
* But see FIXME_VIEW_COORD_SYS_SYNC_BACK for some existing bugs.
*
* [VIEW_COORD_SYS_UPDATE_FLOW]:
* To avoid bidirectional flow, we consider the original inputs (center/zoom/dataRect/viewRect/etc.) as
* the single source of truth, and always calculate transformations based on that.
* - Roaming interactions ('pan'/'zoom') can trigger an update to the original inputs via
* `dispatchAction({type: 'xxxRoam', ...})`.
* - Roaming animation can synchronize back to the original inputs when interrupted.
* See `syncBackEl`: It is zrender elements that are assigned with VIEW_COORD_SYS_TRANSFORMATION,
* and may be modified outside, typically by animation.
*/
/**
* @tutorial [VIEW_COORD_SYS_TRANSFORMATION]
*
* @tutorial [VIEW_COORD_SYS_TRANS_RAW]
* It is the transformation from `ViewInner['dataRect']` to `ViewInner['viewRect']`.
* - ViewInner['dataRect']:
* A rect in a source space (or say, data space).
* The unit is defined by the source. For example,
* - for geo source, the unit defined as lat/lng,
* - for SVG source, the unit is the same as the width/height defined in SVG.
* - for series.graph/series.tree/series.sankey, the unit defined as px directly.
* - ViewInner['viewRect']:
* A rect in the canvas pixel space.
* For example, it can be ec option left/right/top/bottom/width/height of a component or series.
* NOTICE:
* - ViewInner['dataRect'] and ViewInner['viewRect'] affect the behavior when centerOption contains
* absolute values. See VIEW_COORD_SYS_CENTER_ZOOM_DEFINITION .
*
* @tutorial [VIEW_COORD_SYS_TRANS_ROAM]
* It is built with respect to `RoamOptionMixin['center']` and `RoamOptionMixin['zoom']`.
* [VIEW_COORD_SYS_CENTER_ZOOM_DEFINITION]:
* {pxSpace} <-roamTrans- {viewRectSpace} <-rawTrans- {dataRectSpace} <-- ...
* | |
* zoomOption centerOption
* `RoamOptionMixin['center']` is a user specified point on the space of `ViewInner['dataRect']`,
* which will be located to the center of `ViewInner['viewRect']`.
* It can also be a percent value (e.g. '50%'), based on ViewInner['dataRect'].width/height` (since v6).
* Under this definition, users can use '0%' to map the top-left of `ViewInner['dataRect']`
* to the center of `ViewInner['viewRect']`.
* NOTICE:
* - `RoamOptionMixin['center']` is in a linear space regardless of `GeoCommonOptionMixin['projection']`
* - Absolute values in centerOption may hardly have a rigorous meaningful definition if the layout
* is auto-calculated, since users are unlikely to known the exact value of the bounding rect.
* And it is affected by the settings of ViewInner['dataRect'] and ViewInner['viewRect'].
* Therefore, percent centerOption is preferred.
* Use cases:
* geo and map series (`MapDraw`) use this transformation for roamming, since the source
* has been converted with respect to VIEW_COORD_SYS_TRANS_RAW.
*
* @tutorial [VIEW_COORD_SYS_TRANS_OVERALL]
* This is the result of
* `matrix_left_multiply(VIEW_COORD_SYS_TRANS_ROAM, VIEW_COORD_SYS_TRANS_RAW)`.
* Use case:
* sankey/tree/graph series use this transformation for roamming.
*
* @tutorial [VIEW_COORD_SYS_TRANSFORMATION_FORMULA]
* [Basic]:
* {pxSpace} <-roamTrans- {viewRectSpace} <-rawTrans- {dataRectSpace} <-- ...
* pxPoint = roamTrans * rawTrans * dataPoint
* overallTrans = roamTrans * rawTrans
* [e.g., geo case]:
* pxPoint = roamTrans * (rawTrans * (projection * dataPoint))
* Hence: pxPoint = group_syncBackType_ROAM * (rawTrans * (projection * dataPoint))
* Hence: pxPoint = group_syncBackType_ROAM * rawTrans_projection_precalculated_point
* [e.g., graph series case]:
* pxPoint = (roamTrans * rawTrans) * upper_els
* Hence: pxPoint = group_syncBackType_OVERALL * upper_els
* (NOTE: upper_els can have their own transformations)
*
* @see viewCoordSysCopyTrans for fetching transformations.
*/
export var VIEW_COORD_SYS_TRANS_RAW = 0;
export var VIEW_COORD_SYS_TRANS_ROAM = 1;
export var VIEW_COORD_SYS_TRANS_OVERALL = 2;
function inner(viewCoordSys) {
return viewCoordSys;
}
export var VIEW_COORD_SYS_TYPE = 'view';
/**
* [VIEW_COORD_SYS]
*
* @final [NOTICE] Inheritance of this class is not recommended. Use composition instead.
*/
var View = /** @class */function (_super) {
__extends(View, _super);
function View(invertY, legacyCenterBase, legacyGeo) {
var _this = _super.call(this) || this;
_this.type = VIEW_COORD_SYS_TYPE;
_this.dimensions = ['x', 'y'];
var viewInner = inner(_this);
viewInner.invertY = invertY;
viewInner.lgCt = legacyCenterBase;
viewInner.lgGeo = legacyGeo;
var trans = viewInner.trans = [];
trans[VIEW_COORD_SYS_TRANS_RAW] = transformableCreate();
trans[VIEW_COORD_SYS_TRANS_ROAM] = transformableCreate();
trans[VIEW_COORD_SYS_TRANS_OVERALL] = transformableCreate();
viewInner.mtRaw = matrixCreate();
viewInner.mtRawInv = matrixCreate();
viewInner.mtOverall = matrixCreate();
viewInner.mtOverallInv = matrixCreate();
viewInner.zoom = 1;
return _this;
}
/**
* @implements CoordinateSystem['getBoundingRect']
* @see VIEW_COORD_SYS_TRANS_RAW
*
* This is a rect in data space.
* For historicall reason, the name is `getBoundingRect` - preserve it for backward compatibility.
*/
View.prototype.getBoundingRect = function () {
return viewCoordSysCopyBoundingRect(null, this);
};
/**
* @implements CoordinateSystem['getViewRect']
* @see VIEW_COORD_SYS_TRANS_RAW
*/
View.prototype.getViewRect = function () {
return viewCoordSysCopyViewRect(null, this);
};
/**
* @implements CoordinateSystem['getRoamTransform']
*/
View.prototype.getRoamTransform = function () {
return transformableGetLocalTransform(inner(this).trans[VIEW_COORD_SYS_TRANS_ROAM]);
};
View.prototype.dataToPoint = function (data, noRoam, out) {
var transform = noRoam ? inner(this).mtRaw : inner(this).mtOverall;
out = out || [];
return transform ? vectorApplyTransform(out, data, transform) : vectorCopy(out, data);
};
View.prototype.pointToData = function (point, reserved, out) {
out = out || [];
var invTransform = inner(this).mtOverallInv;
return invTransform ? vectorApplyTransform(out, point, invTransform) : vectorCopy(out, point);
};
View.prototype.convertToPixel = function (ecModel, finder, value) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.dataToPoint(value) : null;
};
View.prototype.convertFromPixel = function (ecModel, finder, pixel) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.pointToData(pixel) : null;
};
View.prototype.containPoint = function (point) {
var viewInner = inner(this);
boundingRectCopy(tmpPixelRectForContain, viewInner.dataRect);
boundingRectApplyTransform(tmpPixelRectForContain, tmpPixelRectForContain, viewInner.mtOverall);
return boundingRectContain(tmpPixelRectForContain, point[0], point[1]);
};
View.dimensions = ['x', 'y'];
return View;
}(Transformable);
var tmpPixelRectForContain = boundingRectCreate();
export function viewCoordSysCopyOverallMatrix(out, viewCoordSys) {
return matrixCopy(out || [], inner(viewCoordSys).mtOverall);
}
export function viewCoordSysGetZoomOption(viewCoordSys) {
return inner(viewCoordSys).zoom;
}
export function viewCoordSysCopyBoundingRect(out, viewCoordSys) {
return boundingRectCopy(out || boundingRectCreate(), inner(viewCoordSys).dataRect);
}
export function viewCoordSysCopyViewRect(out, viewCoordSys) {
return boundingRectCopy(out || boundingRectCreate(), inner(viewCoordSys).viewRect);
}
export function viewCoordSysCopyTrans(out, viewCoordSys, transKind
// @return The input `out` or create an object.
) {
return copyTransform(out || transformableCreate(), inner(viewCoordSys).trans[transKind]);
}
function viewCoordSysIsInputReady(viewInner) {
return !!(viewInner.dataRect && viewInner.viewRect);
// NOTE: Other parameters has default values. Only parameters
// above are required to be input.
}
function calcOverallTransFromSyncBackEl(out, viewInner, syncBackEl, syncBackType) {
if (syncBackType === VIEW_COORD_SYS_TRANS_ROAM) {
calcOverallTrans(out, viewInner.trans[VIEW_COORD_SYS_TRANS_RAW], syncBackEl);
} else {
copyTransform(out, syncBackEl);
}
}
function calcRoamTransFromOverallTrans(out, viewInner, overallTrans) {
// Convert overallTrans to roamTrans. If update animation is applied to overallTrans,
// we assume that rawTrans is changed instantly, and roamTrans takes that animation.
// Formula:
// overallTrans = roamTrans * rawTrans
// overallTrans * invert(rawTrans) = roamTrans
transformableGetLocalTransform(overallTrans, tmpMtRTO);
matrixMul(tmpMtRTO, tmpMtRTO, viewInner.mtRawInv);
decomposeTransform(out, tmpMtRTO);
}
var tmpMtRTO = matrixCreate();
/**
* [NOTICE]
* The definition of this center has always been irrelevant to some other series center like
* 'series-pie.center' - this center is a point in the space of `ViewInner['dataRect'].x/y`,
* rather than canvas viewport, and the unit is not necessarily pixel (e.g., in geo case).
*/
export function viewCoordSysSetRoamOptionFromModel(viewCoordSys, hostModel) {
var viewInner = inner(viewCoordSys);
viewInner.centerOption = hostModel.getShallow('center');
var zoomLimit = viewInner.zoomLimit = hostModel.getShallow('scaleLimit');
var zoomOption = hostModel.getShallow('zoom');
viewInner.zoom = clampByZoomLimit(zoomOption || 1, zoomLimit) || 1;
if (viewCoordSysIsInputReady(viewInner)) {
viewCoordSysUpdateTransform(viewInner);
}
}
/**
* @see ViewInner['dataRect']
*/
export function viewCoordSysSetBoundingRect(viewCoordSys, x, y, width, height) {
var viewInner = inner(viewCoordSys);
viewInner.dataRect = new BoundingRect(x, y, width, height);
if (viewCoordSysIsInputReady(viewInner)) {
viewCoordSysUpdateTransform(viewInner);
}
}
/**
* @see ViewInner['viewRect']
*/
export function viewCoordSysSetViewRect(viewCoordSys, x, y, width, height) {
var viewInner = inner(viewCoordSys);
viewInner.viewRect = new BoundingRect(x, y, width, height);
if (viewCoordSysIsInputReady(viewInner)) {
viewCoordSysUpdateTransform(viewInner);
}
}
function viewCoordSysUpdateTransform(viewInner) {
// The order matters.
viewCoordSysUpdateRawTrans(viewInner);
viewCoordSysUpdateRoamTrans(viewInner);
viewCoordSysUpdateOverallTrans(viewInner);
}
function viewCoordSysUpdateRawTrans(viewInner) {
var dataRect = viewInner.dataRect;
var viewRect = viewInner.viewRect;
var rawTrans = viewInner.trans[VIEW_COORD_SYS_TRANS_RAW];
var invertY = viewInner.invertY;
if (invertY) {
dataRect = boundingRectCopy(tmpRectURT, dataRect);
dataRect.y = -dataRect.y - dataRect.height;
}
boundingRectCalculateTransform(tmpMtURT, dataRect, viewRect);
decomposeTransform(rawTrans, tmpMtURT);
if (invertY) {
rawTrans.scaleY = -rawTrans.scaleY;
}
var mtRaw = transformableGetLocalTransform(rawTrans, viewInner.mtRaw);
matrixInvert(viewInner.mtRawInv, mtRaw);
}
var tmpMtURT = matrixCreate();
var tmpRectURT = boundingRectCreate();
/**
* NOTICE: It depends on `viewCoordSysUpdateRawTrans`.
*/
function viewCoordSysUpdateRoamTrans(viewInner) {
var viewRectCenter = viewCoordSysGetViewRectCenter(viewInner);
var roamViewCenter = parseCenterOption(tmpCenterURT, viewInner, viewInner.centerOption) ? vectorApplyTransform(tmpCenterURT, tmpCenterURT, viewInner.mtRaw) : viewRectCenter;
var zoom = viewInner.zoom;
var roamTrans = viewInner.trans[VIEW_COORD_SYS_TRANS_ROAM];
roamTrans.x = viewRectCenter[0] - zoom * roamViewCenter[0];
roamTrans.y = viewRectCenter[1] - zoom * roamViewCenter[1];
roamTrans.scaleX = roamTrans.scaleY = zoom;
// [VIEW_COORD_SYS_APPLY_ROAM_CENTER_AND_ZOOM]
// Ordinarily, the definition is:
// roamTrans.originX = roamViewCenter[0];
// roamTrans.originY = roamViewCenter[1];
// roamTrans.x = viewRectCenter[0] - roamViewCenter[0];
// roamTrans.y = viewRectCenter[1] - roamViewCenter[1];
// roamTrans.scaleX = roamTrans.scaleY = zoom;
// But `el.originX`/`originY` should not be set.
// (see VIEW_COORD_SYS_ANIMATION_PROPS_CONSTRAINT for the reason),
// so we use the above formula instead.
}
var tmpCenterURT = [];
/**
* NOTICE: It depends on `viewCoordSysUpdateRoamTrans` and `viewCoordSysUpdateRawTrans`
*/
function viewCoordSysUpdateOverallTrans(viewInner) {
var trans = viewInner.trans;
var roamTrans = trans[VIEW_COORD_SYS_TRANS_ROAM];
var rawTrans = trans[VIEW_COORD_SYS_TRANS_RAW];
var overallTrans = trans[VIEW_COORD_SYS_TRANS_OVERALL];
calcOverallTrans(overallTrans, rawTrans, roamTrans);
var mtOverall = transformableGetLocalTransform(overallTrans, viewInner.mtOverall);
var mtOverallInv = matrixInvert(viewInner.mtOverallInv, mtOverall);
legacyCopyOverallTrans(viewInner, overallTrans, mtOverall, mtOverallInv);
legacyCopyOverallTrans(viewInner.lgGeo, overallTrans, mtOverall, mtOverallInv);
}
/**
* [VIEW_COORD_SYS_TRANS_OVERALL_BACKWARD_COMPATIBILITY]
* VIEW_COORD_SYS_TRANS_OVERALL transformable has long been View or Geo instance itself.
* We keep backward compatibility, since some users may have visited it directly (e.g.
* for drawing a computed bounding rect).
*/
function legacyCopyOverallTrans(target, overallTrans, mtOverall, mtOverallInv) {
if (target) {
copyTransform(target, overallTrans);
matrixCopy(target.transform || (target.transform = []), mtOverall);
matrixCopy(target.invTransform || (target.invTransform = []), mtOverallInv);
}
}
function calcOverallTrans(out, rawTrans, roamTrans) {
transformableGetLocalTransform(rawTrans, tmpMtCOT1);
transformableGetLocalTransform(roamTrans, tmpMtCOT2);
matrixMul(tmpMtCOT2, tmpMtCOT2, tmpMtCOT1);
decomposeTransform(out, tmpMtCOT2);
}
var tmpMtCOT1 = matrixCreate();
var tmpMtCOT2 = matrixCreate();
function getCoordSys(finder) {
var seriesModel = finder.seriesModel;
return seriesModel ? seriesModel.coordinateSystem : null; // e.g., graph.
}
function viewCoordSysGetViewRectCenter(viewInner) {
var viewRect = viewInner.viewRect;
tmpViewRectCenter[0] = viewRect.x + viewRect.width / 2;
tmpViewRectCenter[1] = viewRect.y + viewRect.height / 2;
return tmpViewRectCenter;
}
var tmpViewRectCenter = [];
export function isViewCoordSys(coordSys) {
return coordSys && coordSys.type === 'view';
}
/**
* NOTICE:
* - `syncBackEl` should be in the pixel space without any other transformation
* in its accesters, otherwise the roaming may incorrect.
* - `syncBackEl` can be a `Group`, having its own descendants and transformation.
* But in this case, `dataToPoint` can only reach the space of `syncBackEl` itself.
*/
export function applyViewCoordSysTransToElement(syncBackEl, syncBackType, viewCoordSys,
// If NullUndefined, no animation.
// Typically, there should be no animation in the first render and in `__updateOnOwnRoam`.
animatableModel) {
var viewInner = inner(viewCoordSys);
viewInner.syncBackEl = syncBackEl;
viewInner.syncBackType = syncBackType;
if (!animatableModel) {
viewCoordSysCopyTrans(syncBackEl, viewCoordSys, syncBackType);
syncBackEl.dirty();
} else {
updateProps(syncBackEl, viewCoordSysCopyTrans(null, viewCoordSys, syncBackType), animatableModel);
}
}
/**
* FIXME: [FIXME_VIEW_COORD_SYS_SYNC_BACK]
* Currently the "sync back" is only performed on roam action. But these cases are not
* covered:
* 1. Consider both center change and series data adding is requested via `setOption`
* and animation is not finished, the new added series symbols should lay out based
* on the "intermediate state" rather than the "final state" of the VIEW_COORD_SYS,
* otherwise, visual artifacts can arise.
* 2. See the case of FIXME_SYMBOL_CLIP_CONSIDERING_COORD_SYS_ALIGNMENT_DURING_ANIMATION .
*/
function viewCoordSysSyncBack(viewCoordSys, hostModel, otherModelsToSync, payload) {
var viewInner = inner(viewCoordSys);
var syncBackEl = viewInner.syncBackEl;
if (syncBackEl) {
if (process.env.NODE_ENV !== 'production') {
assert(viewInner.syncBackType != null);
}
// @see VIEW_COORD_SYS_ANIMATION_INTERRUPTION
syncBackEl.stopAnimation();
// syncBackEl may have been changed regardless of animation,
// therefore, need to sync back.
calcOverallTransFromSyncBackEl(tmpTransSB1, viewInner, syncBackEl, viewInner.syncBackType);
} else {
copyTransform(tmpTransSB1, viewInner.trans[VIEW_COORD_SYS_TRANS_OVERALL]);
}
// Sync back to model.
calcRoamTransFromOverallTrans(tmpTransSB2, viewInner, tmpTransSB1);
payload ? applyRoamPayloadToOverallTrans(tmpTransSB1, tmpTransSB2, viewInner, payload) : copyTransform(tmpTransSB1, tmpTransSB2);
calcRoamTransFromOverallTrans(tmpTransSB1, viewInner, tmpTransSB1);
syncBackToRoamOptionFromRoamTrans(viewInner, hostModel, otherModelsToSync, tmpTransSB1);
}
var tmpTransSB1 = transformableCreate();
var tmpTransSB2 = transformableCreate();
/**
* Invert to `center` and `zoom` of VIEW_COORD_SYS and host models based on
* - `syncBackEl` or VIEW_COORD_SYS_TRANS_OVERALL
* - Delta in `payload`.
*
* Should be only called in action handlers.
*
* @see RoamHostView['__updateOnOwnRoam']
*/
export function ownRoamModelCoordSysUpdateInAction(payload, hostModel,
// This is only used for MAP_SERIES_GROUP, where the change need to sync to all series,
// otherwise when legend filter some series and the other series take the responsibility
// to draw map, or roam then legend restored, the result will be incorrect.
otherModelsToSync) {
// NOTE: VIEW_COORD_SYS instances are depended on by this action handler.
// Under the current design, actions should not be triggered before `setOption`
// being called, therefore coord sys instances always exist.
var viewCoordSys = getOwnRoamViewCoordSys(hostModel);
if (viewCoordSys) {
// Sync back to model.
viewCoordSysSyncBack(viewCoordSys, hostModel, otherModelsToSync, payload);
// Recalculate from model.
viewCoordSysSetRoamOptionFromModel(viewCoordSys, hostModel);
}
}
export function getOwnRoamViewCoordSys(hostModel) {
return hostModel.__ownRoamView ? hostModel.__ownRoamView() : null;
}
export function ownRoamViewUpdateDirectlyInAction(payload, componentOrSeries, ecModel, api) {
// Tricky: disable animation in `updateProps` of `graphic.ts`.
ecModel.setUpdatePayload(payloadDisableAnimation(payload));
var componentOrSeriesView = getViewOfComponentOrSeries(api, componentOrSeries);
if (componentOrSeriesView && componentOrSeriesView.__updateOnOwnRoam) {
componentOrSeriesView.__updateOnOwnRoam(payload, componentOrSeries, api);
}
}
function applyRoamPayloadToOverallTrans(targetOverallTrans, roamTrans, viewInner, payload) {
// NOTE: payload.dx/dy should always applied to pixel space, i.e., "overallTrans".
if (payload.dx != null && payload.dy != null) {
targetOverallTrans.x += payload.dx;
targetOverallTrans.y += payload.dy;
}
var deltaZoom = payload.zoom;
if (deltaZoom != null) {
// Although `zoomOption` is defined on roamTrans
var oldZoom = getZoomFromRoamTrans(roamTrans);
var newZoom = clampByZoomLimit(oldZoom * deltaZoom, viewInner.zoomLimit);
var deltaZoom2 = newZoom / oldZoom;
// Keep the mouse center when scaling.
targetOverallTrans.x -= (payload.originX - targetOverallTrans.x) * (deltaZoom2 - 1);
targetOverallTrans.y -= (payload.originY - targetOverallTrans.y) * (deltaZoom2 - 1);
// Although `zoomOption` is defined on roamTrans,
// deltaZoom can be applied to overallTrans directly.
targetOverallTrans.scaleX *= deltaZoom2;
targetOverallTrans.scaleY *= deltaZoom2;
}
}
function getZoomFromRoamTrans(trans) {
if (process.env.NODE_ENV !== 'production') {
// scaleX and scaleY should be the same even during animation.
// See VIEW_COORD_SYS_APPLY_ROAM_CENTER_AND_ZOOM .
assert(mathAbs(trans.scaleX - trans.scaleY) < 1e-5);
}
return trans.scaleX;
}
function parseCenterOption(
// `out` is a center in `dataRect` space.
out, viewInner, centerOption
// @return Whether a valid center is obtained.
) {
if (process.env.NODE_ENV !== 'production') {
assert(viewCoordSysIsInputReady(viewInner));
}
var dataRect = viewInner.dataRect;
if (!centerOption) {
return false;
}
// #16904 introduced percentage string here, such as '33%'. But it was based on canvas
// width/height, which is not reasonable - the unit may incorrect, and it is unpredictable if
// the `ViewInner['dataRect']` is not calculated based on the current canvas rect. Therefore the percentage
// value is changed to based on `ViewInner['dataRect'].width/height` since v6. Under this definition, users
// can use '0%' to map the top-left of `ViewInner['dataRect']` to the center of `ViewInner['viewRect']`.
var lgCt = viewInner.lgCt;
if (lgCt) {
vectorSet(out, parsePercent(centerOption[0], lgCt.w), parsePercent(centerOption[1], lgCt.h));
} else if (dataRect) {
vectorSet(out, parsePercent(centerOption[0], dataRect.width, dataRect.x), parsePercent(centerOption[1], dataRect.height, dataRect.y));
}
return true;
}
/**
* An inverse operation to `parseCenterOption`.
* Mainly for percentage center option.
*/
function invertBackToCenterOption(viewInner, center) {
var lastCenterOption = viewInner.centerOption;
var dataRect = viewInner.dataRect;
if (process.env.NODE_ENV !== 'production') {
assert(center && dataRect);
}
return !lastCenterOption || viewInner.lgCt ? center.slice() : [invertToPercentPerCenterDim(0, center, lastCenterOption, dataRect), invertToPercentPerCenterDim(1, center, lastCenterOption, dataRect)];
}
function invertToPercentPerCenterDim(dimIdx, center, lastCenterOption, dataRect) {
return lastCenterOption && dataRect && dataRect[WH[dimIdx]] && isPositionSizeOptionPercent(lastCenterOption[dimIdx]) ? (center[dimIdx] - dataRect[XY[dimIdx]]) / dataRect[WH[dimIdx]] * 100 + '%' : center[dimIdx];
}
export function useLegacyViewCoordSysCenterBase(ecModel, api) {
return api && ecModel && ecModel.getShallow('legacyViewCoordSysCenterBase') ? {
w: api.getWidth(),
h: api.getHeight()
} : null;
}
/**
* @see VIEW_COORD_SYS_ANIMATION_INTERRUPTION
*/
function syncBackToRoamOptionFromRoamTrans(viewInner, hostModel, otherModelsToSync, roamTrans) {
// This is the inverse operation of `viewCoordSysSetRoamOptionFromModel`.
var viewRectCenter = viewCoordSysGetViewRectCenter(viewInner);
var zoom = getZoomFromRoamTrans(roamTrans);
var notZoomNearZero = mathAbs(zoom) > 1e-6;
tmpCenterITR[0] = notZoomNearZero ? (viewRectCenter[0] - roamTrans.x) / zoom : viewRectCenter[0]; // Unlikely to occur.
tmpCenterITR[1] = notZoomNearZero ? (viewRectCenter[1] - roamTrans.y) / zoom : viewRectCenter[1]; // Unlikely to occur.
vectorApplyTransform(tmpCenterITR, tmpCenterITR, viewInner.mtRawInv);
var centerOption = invertBackToCenterOption(viewInner, tmpCenterITR);
syncBackRoamOptionToRoamHostModel(hostModel, centerOption, zoom);
each(otherModelsToSync, function (otherModel) {
if (otherModel !== hostModel) {
syncBackRoamOptionToRoamHostModel(otherModel, centerOption.slice(), zoom);
}
});
}
var tmpCenterITR = [];
/**
* Models should be updated, otherwise consequent `setOption()` can cause outdated `center`
* and `zoom` to be used.
*/
function syncBackRoamOptionToRoamHostModel(hostModel, center, zoom) {
var option = hostModel.option;
option.center = center;
option.zoom = zoom;
}
export function clampByZoomLimit(zoom, zoomLimit) {
if (zoomLimit) {
var zoomMin = zoomLimit.min || 0;
var zoomMax = zoomLimit.max || Infinity;
zoom = Math.max(Math.min(zoomMax, zoom), zoomMin);
}
return zoom;
}
export function calcCompensationScaleToPreserveNodeSize(viewCoordSys, model) {
var nodeScaleRatio = model.getShallow('nodeScaleRatio', true) || 1;
var viewInner = inner(viewCoordSys);
// Scale node when zoom changes
return ((viewInner.zoom - 1) * nodeScaleRatio + 1) / (viewInner.trans[VIEW_COORD_SYS_TRANS_OVERALL].scaleX || 1);
}
export default View;
+319
View File
@@ -0,0 +1,319 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { getAcceptableTickPrecision, isNullableNumberFinite, mathAbs, mathCeil, mathFloor, mathMax, mathRound, nice, NICE_MODE_MIN, quantity, round } from '../util/number.js';
import IntervalScale from '../scale/Interval.js';
import LogScale from '../scale/Log.js';
import { updateIntervalOrLogScaleForNiceOrAligned } from './axisHelper.js';
import { warn } from '../util/log.js';
import { increaseInterval, isLogScale, getIntervalPrecision, intervalScaleEnsureValidExtent } from '../scale/helper.js';
import { assert } from 'zrender/lib/core/util.js';
import { adoptScaleRawExtentInfoAndPrepare } from './scaleRawExtentInfo.js';
import { hasBreaks } from '../scale/break.js';
/**
* NOTE: See the summary of the process of extent determination in the comment of `scaleMapper.setExtent`.
*
* @see SCALE_EXTENT_CONSTRUCTION for the full processing flow.
*/
export function scaleCalcAlign(targetAxis, alignToScale) {
var targetScale = targetAxis.scale;
var targetAxisModel = targetAxis.model;
if (process.env.NODE_ENV !== 'production') {
assert(targetScale && targetAxisModel && (targetScale instanceof IntervalScale || targetScale instanceof LogScale) && (alignToScale instanceof IntervalScale || alignToScale instanceof LogScale));
}
var targetExtentInfo = adoptScaleRawExtentInfoAndPrepare(targetScale, targetAxisModel, targetAxisModel.ecModel, targetAxis, null);
// FIXME:
// (1) Axis inverse is not considered yet.
// (2) `SCALE_EXTENT_KIND_MAPPING` is not considered yet.
var isTargetLogScale = isLogScale(targetScale);
var alignToScaleLinear = isLogScale(alignToScale) ? alignToScale.intervalStub : alignToScale;
var targetIntervalStub = isTargetLogScale ? targetScale.intervalStub : targetScale;
var targetLogScaleBase = targetScale.base;
var alignToTicks = alignToScaleLinear.getTicks();
var alignToExpNiceTicks = alignToScaleLinear.getTicks({
expandToNicedExtent: true
});
var alignToSegCount = alignToTicks.length - 1;
if (process.env.NODE_ENV !== 'production') {
// This is guards for future changes of `Interval#getTicks`.
assert(!hasBreaks(alignToScale) && !hasBreaks(targetScale));
assert(alignToSegCount > 0); // Ticks length >= 2 even on a blank scale.
assert(alignToExpNiceTicks.length === alignToTicks.length);
assert(alignToTicks[0].value <= alignToTicks[alignToSegCount].value);
assert(alignToExpNiceTicks[0].value <= alignToTicks[0].value && alignToTicks[alignToSegCount].value <= alignToExpNiceTicks[alignToSegCount].value);
if (alignToSegCount >= 2) {
assert(alignToExpNiceTicks[1].value === alignToTicks[1].value);
assert(alignToExpNiceTicks[alignToSegCount - 1].value === alignToTicks[alignToSegCount - 1].value);
}
}
// The Current strategy: Find a proper interval and an extent for the target scale to derive ticks
// matching exactly to ticks of `alignTo` scale.
// Adjust min, max based on the extent of alignTo. When min or max is set in alignTo scale
var t0; // diff ratio on min not-nice segment. 0 <= t0 < 1
var t1; // diff ratio on max not-nice segment. 0 <= t1 < 1
var alignToNiceSegCount; // >= 1
// Consider ticks of `alignTo`, only these cases below may occur:
if (alignToSegCount === 1) {
// `alignToTicks` is like:
// |--|
// In this case, we make the corresponding 2 target ticks "nice".
t0 = t1 = 0;
alignToNiceSegCount = 1;
} else if (alignToSegCount === 2) {
// `alignToTicks` is like:
// |-|-----| or
// |-----|-| or
// |-----|-----|
// Notices that nice ticks do not necessarily exist in this case.
// In this case, we choose the larger segment as the "nice segment" and
// the corresponding target ticks are made "nice".
var interval0 = mathAbs(alignToTicks[0].value - alignToTicks[1].value);
var interval1 = mathAbs(alignToTicks[1].value - alignToTicks[2].value);
t0 = t1 = 0;
if (interval0 === interval1) {
alignToNiceSegCount = 2;
} else {
alignToNiceSegCount = 1;
if (interval0 < interval1) {
t0 = interval0 / interval1;
} else {
t1 = interval1 / interval0;
}
}
} else {
// alignToSegCount >= 3
// `alignToTicks` is like:
// |-|-----|-----|-| or
// |-----|-----|-| or
// |-|-----|-----| or ...
// At least one nice segment is present, and not-nice segments are only present on
// the start and/or the end.
// In this case, ticks corresponding to nice segments are made "nice".
var alignToInterval = alignToScaleLinear.getConfig().interval;
t0 = (1 - (alignToTicks[0].value - alignToExpNiceTicks[0].value) / alignToInterval) % 1;
t1 = (1 - (alignToExpNiceTicks[alignToSegCount].value - alignToTicks[alignToSegCount].value) / alignToInterval) % 1;
alignToNiceSegCount = alignToSegCount - (t0 ? 1 : 0) - (t1 ? 1 : 0);
}
if (process.env.NODE_ENV !== 'production') {
assert(alignToNiceSegCount >= 1);
}
// NOTE:
// Consider a case:
// dataZoom controls all Y axes;
// dataZoom end is 90% (maxFixed: true, dataZoomFixMinMax[0]: true);
// but dataZoom start is 0% (minFixed: false, dataZoomFixMinMax[1]: false);
// In this case,
// - `Interval#calcNiceTicks` only uses `targetExtentInfo.max` as the upper bound, but expand the
// lower bound to a "nice" tick and can get an acceptable result.
// - `scaleCalcAlign` has to use both `targetExtentInfo.min/max` as the bounds without any expansion,
// otherwise the lower bound may become negative unexpectedly, especially for all positive series data.
var dataZoomFixMinMax = targetExtentInfo.zoomFixMM;
var hasDataZoomFixMinMax = dataZoomFixMinMax[0] || dataZoomFixMinMax[1];
var targetMinMaxFixed = [targetExtentInfo.fixMM[0] || hasDataZoomFixMinMax, targetExtentInfo.fixMM[1] || hasDataZoomFixMinMax];
// MEMO: When only `xxxAxis.min` or `xxxAxis.max` is fixed,
// - Even a "nice" interval can be calculated, ticks accumulated based on `min`/`max` can be "nice" only if
// `min` or `max` is a "nice" number.
// - Generating a "nice" interval may cause the extent have both positive and negative ticks, which may be
// not preferable for all positive (very common) or all negative series data. But it can be simply resolved
// by specifying `xxxAxis.min: 0`/`xxxAxis.max: 0`, so we do not specially handle this case here.
// Therefore, we prioritize generating "nice" interval over preventing from crossing zero.
// e.g., if series data are all positive and the max data is `11739`,
// If setting `yAxis.max: 'dataMax'`, ticks may be like:
// `11739, 8739, 5739, 2739, -1739` (not "nice" enough)
// If setting `yAxis.max: 'dataMax', yAxis.min: 0`, ticks may be like:
// `11739, 8805, 5870, 2935, 0` (not "nice" enough but may be acceptable)
// If setting `yAxis.max: 12000, yAxis.min: 0`, ticks may be like:
// `12000, 9000, 6000, 3000, 0` ("nice")
var targetOldOutermostExtent = targetScale.getExtent();
var targetOldIntervalExtent = targetIntervalStub.getExtent();
var targetExtent = intervalScaleEnsureValidExtent(targetOldIntervalExtent, targetMinMaxFixed);
var min;
var max;
var interval;
var intervalPrecision;
var maxNice;
var minNice;
function loopIncreaseInterval(cb) {
// Typically this loop runs less than 5 times. But we still
// use a fail-safe for future changes.
var LOOP_MAX = 50;
var loopGuard = 0;
for (; loopGuard < LOOP_MAX; loopGuard++) {
if (cb()) {
break;
}
interval = isTargetLogScale
// TODO: `mathMax(base, 2)` is a guardcode to avoid infinite loop,
// but probably it should be guranteed by `LogScale` itself.
? interval * mathMax(targetLogScaleBase, 2) : increaseInterval(interval);
intervalPrecision = getIntervalPrecision(interval);
}
if (process.env.NODE_ENV !== 'production') {
if (loopGuard >= LOOP_MAX) {
warn('incorrect impl in `scaleCalcAlign`.');
}
}
}
function updateMinFromMinNice() {
min = round(minNice - interval * t0, intervalPrecision);
}
function updateMaxFromMaxNice() {
max = round(maxNice + interval * t1, intervalPrecision);
}
function updateMinNiceFromMinT0Interval() {
minNice = t0 ? round(min + interval * t0, intervalPrecision) : min;
}
function updateMaxNiceFromMaxT1Interval() {
maxNice = t1 ? round(max - interval * t1, intervalPrecision) : max;
}
// NOTE: The new calculated `min`/`max` must NOT shrink the original extent; otherwise some series
// data may be outside of the extent. They can expand the original extent slightly to align with
// ticks of `alignTo`. In this case, more blank space is added but visually fine.
if (targetMinMaxFixed[0] && targetMinMaxFixed[1]) {
// Both `min` and `max` are specified (via dataZoom or ec option; consider both Cartesian, radar and
// other possible axes). In this case, "nice" ticks can hardly be calculated, but reasonable ticks should
// still be calculated whenever possible, especially `intervalPrecision` should be tuned for better
// appearance and lower cumulative error.
min = targetExtent[0];
max = targetExtent[1];
interval = (max - min) / (alignToNiceSegCount + t0 + t1);
// Typically axis pixel extent is ready here. See `create` in `Grid.ts`.
var axisPxExtent = targetAxis.getExtent();
// NOTICE: this pxSpan may be not accurate yet due to "outerBounds" logic, but acceptable so far.
var pxSpan = mathAbs(axisPxExtent[1] - axisPxExtent[0]);
// We imperically choose `pxDiffAcceptable` as `0.5 / alignToNiceSegCount` for reduce cumulative
// error, otherwise a discernible misalign (> 1px) may occur.
// PENDING: We do not find a acceptable precision for LogScale here.
// Theoretically it can be addressed but introduce more complexity. Is it necessary?
intervalPrecision = getAcceptableTickPrecision([max, min], pxSpan, 0.5 / alignToNiceSegCount);
updateMinNiceFromMinT0Interval();
updateMaxNiceFromMaxT1Interval();
if (isNullableNumberFinite(intervalPrecision)) {
interval = round(interval, intervalPrecision);
}
} else {
// Make a minimal enough `interval`, increase it later.
// It is a similar logic as `IntervalScale#calcNiceTicks` and `LogScale#calcNiceTicks`.
// Axis break is not supported, which is guranteed by the caller of this function.
var targetSpan = targetExtent[1] - targetExtent[0];
interval = isTargetLogScale ? mathMax(quantity(targetSpan), 1) : nice(targetSpan / alignToNiceSegCount, NICE_MODE_MIN);
intervalPrecision = getIntervalPrecision(interval);
if (targetMinMaxFixed[0]) {
min = targetExtent[0];
loopIncreaseInterval(function () {
updateMinNiceFromMinT0Interval();
maxNice = round(minNice + interval * alignToNiceSegCount, intervalPrecision);
updateMaxFromMaxNice();
if (max >= targetExtent[1]) {
return true;
}
});
} else if (targetMinMaxFixed[1]) {
max = targetExtent[1];
loopIncreaseInterval(function () {
updateMaxNiceFromMaxT1Interval();
minNice = round(maxNice - interval * alignToNiceSegCount, intervalPrecision);
updateMinFromMinNice();
if (min <= targetExtent[0]) {
return true;
}
});
} else {
loopIncreaseInterval(function () {
minNice = round(mathCeil(targetExtent[0] / interval) * interval, intervalPrecision);
maxNice = round(mathFloor(targetExtent[1] / interval) * interval, intervalPrecision);
// NOTE:
// - `maxNice - minNice >= -interval` here.
// - While `interval` increases, `currIntervalCount` decreases, minimum `-1`.
var currIntervalCount = mathRound((maxNice - minNice) / interval);
if (currIntervalCount <= alignToNiceSegCount) {
var moreCount = alignToNiceSegCount - currIntervalCount;
// Consider cases that negative tick do not make sense (or vice versa), users can simply
// specify `xxxAxis.min/max: 0` to avoid negative. But we still automatically handle it
// for some common cases whenever possible:
// - When ec option is `xxxAxis.scale: false` (the default), it is usually unexpected if
// negative (or positive) ticks are introduced.
// - In LogScale, series data are usually either all > 1 or all < 1, rather than both,
// that is, logarithm result is typically either all positive or all negative.
var moreCountPair = void 0;
var mayEnhanceZero = targetExtentInfo.incl0 || isTargetLogScale;
// `bounds < 0` or `bounds > 0` may require more complex handling, so we only auto handle
// `bounds === 0`.
if (mayEnhanceZero && targetExtent[0] === 0) {
// 0 has been included in extent and all positive.
moreCountPair = [0, moreCount];
} else if (mayEnhanceZero && targetExtent[1] === 0) {
// 0 has been included in extent and all negative.
moreCountPair = [moreCount, 0];
} else {
// Try to center ticks in axis space whenever possible, which is especially preferable
// in `LogScale`.
var lessHalfCount = mathFloor(moreCount / 2);
moreCountPair = moreCount % 2 === 0 ? [lessHalfCount, lessHalfCount] : min + max < targetExtent[0] + targetExtent[1] ? [lessHalfCount, lessHalfCount + 1] : [lessHalfCount + 1, lessHalfCount];
}
minNice = round(minNice - interval * moreCountPair[0], intervalPrecision);
maxNice = round(maxNice + interval * moreCountPair[1], intervalPrecision);
updateMinFromMinNice();
updateMaxFromMaxNice();
if (min <= targetExtent[0] && max >= targetExtent[1]) {
return true;
}
}
});
}
}
updateIntervalOrLogScaleForNiceOrAligned(targetScale, targetMinMaxFixed, targetOldIntervalExtent, [min, max], targetOldOutermostExtent, {
// NOTE: Even in LogScale, `interval` should not be in log space.
interval: interval,
// Force ticks count, otherwise cumulative error may cause more unexpected ticks to be generated.
// Though the overlapping tick labels may be auto-ignored, but probably unexpected, e.g., the min
// tick label is ignored but the secondary min tick label is shown, which is unexpected when
// `axis.min` is user-specified or dataZoom-specified.
intervalCount: alignToNiceSegCount,
intervalPrecision: intervalPrecision,
niceExtent: [minNice, maxNice]
});
if (process.env.NODE_ENV !== 'production') {
targetScale.freeze();
}
}
+163
View File
@@ -0,0 +1,163 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { assert, each } from 'zrender/lib/core/util.js';
import { isOrdinalScale } from '../scale/helper.js';
import { isNullableNumberFinite, mathAbs, mathMax } from '../util/number.js';
import { getAxisStat, getAxisStatBySeries, LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE } from './axisStatistics.js';
import { getScaleLinearSpanForMapping } from '../scale/scaleMapper.js';
// Arbitrary, leave some space to avoid overflowing when dataZoom moving.
var FALLBACK_BAND_WIDTH_RATIO = 0.8;
/**
* NOTICE:
* - Require the axis pixel extent and the scale extent as inputs. But they
* can be not precise for approximation.
* - Can only be called after "data processing" stage.
*
* PENDING:
* Currently `bandWidth` can not be specified by users explicitly. But if we
* allow that in future, these issues must be considered:
* - Can only allow specifying a band width in data scale rather than pixel.
* - LogScale needs to be considered - band width can only be specified on linear
* (but before break) scale, similar to `axis.interval`.
*
* A band is required on:
* - series group band width in bar/boxplot/candlestick/...;
* - tooltip axisPointer type "shadow";
* - etc.
*/
export function calcBandWidth(axis, opt) {
opt = opt || {};
var out = {
w: NaN,
w2: NaN
};
var scale = axis.scale;
var fromStat = opt.fromStat;
var min = opt.min;
// [BAND_WIDTH_USED_SCALE_LINEAR_SPAN]
// - Band width should always respect to the currently specified extent, and `SCALE_EXTENT_KIND_MAPPING`
// should be used if specified.
// Otherwise, the result may incorrect, especially when data count is small.
// For example, when "containShape" is calculating, no `SCALE_EXTENT_KIND_MAPPING` is set, so here only
// `SCALE_EXTENT_KIND_EFFECTIVE` is returned, say, `[3, 5]`, based on which a `SCALE_EXTENT_KIND_MAPPING`
// is calculated, say `[2.5, 5.5]` (expanded by `0.5`). Then when rendering, that `SCALE_EXTENT_KIND_MAPPING`
// is returned here.
// See AXIS_CONTAIN_SHAPE_COMMON_STRATEGY for more details.
// - The span should be in the linear space (typically, the innermost space).
// - We use the scale extent after being zoommed and `intervalScaleEnsureValidExtent`-ish applied and
// "nice"/"align" applied, because:
// - For OrdinalScale, fine;
// - For numeric scale, `scaleLinearSpan` is normally not used for a consistent result when `dataZoom`
// is applied, but used when none or single data item case.
var scaleLinearSpan = getScaleLinearSpanForMapping(scale);
if (!isNullableNumberFinite(scaleLinearSpan)) {
// scale may be `[Infinity, -Infinity]`.
scaleLinearSpan = NaN;
}
var axisExtent = axis.getExtent();
// Always use a new pxSpan because it may be changed in `grid` contain label calculation.
var pxSpan = mathAbs(axisExtent[1] - axisExtent[0]);
if (isOrdinalScale(scale)) {
calcBandWidthForCategoryAxis(out, axis, scaleLinearSpan, pxSpan);
} else if (fromStat) {
calcBandWidthForNumericAxis(out, axis, scaleLinearSpan, pxSpan, fromStat);
} else if (min == null) {
if (process.env.NODE_ENV !== 'production') {
assert(false);
}
}
if (min != null) {
out.w = isNullableNumberFinite(out.w) ? mathMax(min, out.w) : min;
}
return out;
}
function calcBandWidthForCategoryAxis(out, axis, scaleLinearSpan, pxSpan) {
var onBand = axis.onBand;
var len = scaleLinearSpan + (onBand ? 1 : 0);
// Fix #2728, avoid NaN when only one data.
len === 0 && (len = 1);
out.w = pxSpan / len;
// NOTE:
// - When `scaleLinearSpan === 0`, no need to expand extent.
// - `onBand: true` (`boundaryGap: true`) does not need to support `containShape`,
// thereby no `invRatio`.
if (!onBand && scaleLinearSpan && pxSpan) {
out.w2 = out.w * scaleLinearSpan / pxSpan;
}
}
function calcBandWidthForNumericAxis(out, axis, scaleLinearSpan, pxSpan, fromStat) {
if (process.env.NODE_ENV !== 'production') {
assert(fromStat);
}
var onlySingular = false;
var bandWidthInData = -Infinity;
each(fromStat.key ? [getAxisStat(axis, fromStat.key)] : getAxisStatBySeries(axis, fromStat.sers || []), function (stat) {
var liPosMinGap = stat.liPosMinGap;
// NOTE: `liPosMinGap == null` may indicate that `requireAxisStatistics`
// is not used by any series on this axis. We should not make `bandWidth`
// for this case.
if (liPosMinGap != null) {
if (liPosMinGap > 0) {
if (liPosMinGap > bandWidthInData) {
bandWidthInData = liPosMinGap;
}
onlySingular = false;
} else if (liPosMinGap === LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE) {
onlySingular = true;
}
}
});
if (isNullableNumberFinite(scaleLinearSpan) && scaleLinearSpan > 0 && isNullableNumberFinite(bandWidthInData)) {
out.w = pxSpan / scaleLinearSpan * bandWidthInData;
out.w2 = bandWidthInData;
} else if (onlySingular) {
// This is the special handing for single value case, where min gap can not
// be calculated, but `w` and `w2` (for "containShape") are still needed.
out.w = pxSpan * FALLBACK_BAND_WIDTH_RATIO;
out.w2 = out.w * scaleLinearSpan / pxSpan;
// Consider an axis has both candlestick and bar series, where candlestick has multiple data
// but the bar series has no data. In this case, that bar series should be ignored; otherwise,
// the axis will be significantly expanded by "containShape" but no bar shape displayed.
}
}
+49
View File
@@ -0,0 +1,49 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
export var AXIS_TYPES = {
value: 1,
category: 1,
time: 1,
log: 1
};
+239
View File
@@ -0,0 +1,239 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import tokens from '../visual/tokens.js';
var defaultOption = {
show: true,
// zlevel: 0,
z: 0,
// Inverse the axis.
inverse: false,
// Axis name displayed.
name: '',
// 'start' | 'middle' | 'end'
nameLocation: 'end',
// By degree. By default auto rotate by nameLocation.
nameRotate: null,
nameTruncate: {
maxWidth: null,
ellipsis: '...',
placeholder: '.'
},
// Use global text style by default.
nameTextStyle: {
// textMargin: never, // The default value will be specified based on `nameLocation`.
},
// The gap between axisName and axisLine.
nameGap: 15,
// Default `false` to support tooltip.
silent: false,
// Default `false` to avoid legacy user event listener fail.
triggerEvent: false,
tooltip: {
show: false
},
axisPointer: {},
axisLine: {
show: true,
onZero: 'auto',
onZeroAxisIndex: null,
lineStyle: {
color: tokens.color.axisLine,
width: 1,
type: 'solid'
},
// The arrow at both ends the the axis.
symbol: ['none', 'none'],
symbolSize: [10, 15],
breakLine: true
},
axisTick: {
show: true,
// Whether axisTick is inside the grid or outside the grid.
inside: false,
// The length of axisTick.
length: 5,
lineStyle: {
width: 1
}
},
axisLabel: {
show: true,
// Whether axisLabel is inside the grid or outside the grid.
inside: false,
rotate: 0,
// true | false | null/undefined (auto)
showMinLabel: null,
// true | false | null/undefined (auto)
showMaxLabel: null,
margin: 8,
// formatter: null,
fontSize: 12,
color: tokens.color.axisLabel,
// In scenarios like axis labels, when labels text's progression direction matches the label
// layout direction (e.g., when all letters are in a single line), extra start/end margin is
// needed to prevent the text from appearing visually joined. In the other case, when lables
// are stacked (e.g., having rotation or horizontal labels on yAxis), the layout needs to be
// compact, so NO extra top/bottom margin should be applied.
textMargin: [0, 3]
},
splitLine: {
show: true,
showMinLine: true,
showMaxLine: true,
lineStyle: {
color: tokens.color.axisSplitLine,
width: 1,
type: 'solid'
}
},
splitArea: {
show: false,
areaStyle: {
color: [tokens.color.backgroundTint, tokens.color.backgroundTransparent]
}
},
breakArea: {
show: true,
itemStyle: {
color: tokens.color.neutral00,
// Break border color should be darker than the splitLine
// because it has opacity and should be more prominent
borderColor: tokens.color.border,
borderWidth: 1,
borderType: [3, 3],
opacity: 0.6
},
zigzagAmplitude: 4,
zigzagMinSpan: 4,
zigzagMaxSpan: 20,
zigzagZ: 100,
expandOnClick: true
},
breakLabelLayout: {
moveOverlap: 'auto'
}
};
var categoryAxis = zrUtil.merge({
// The gap at both ends of the axis. For categoryAxis, boolean.
boundaryGap: true,
// Set false to faster category collection.
deduplication: null,
jitter: 0,
jitterOverlap: true,
jitterMargin: 2,
// splitArea: {
// show: false
// },
splitLine: {
show: false
},
axisTick: {
// If tick is align with label when boundaryGap is true
alignWithLabel: false,
interval: 'auto',
show: 'auto'
},
axisLabel: {
interval: 'auto'
}
}, defaultOption);
var valueAxis = zrUtil.merge({
boundaryGap: [0, 0],
axisLine: {
// Not shown when other axis is categoryAxis in cartesian
show: 'auto'
},
axisTick: {
// Not shown when other axis is categoryAxis in cartesian
show: 'auto'
},
// TODO
// min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]
splitNumber: 5,
minorTick: {
// Minor tick, not available for cateogry axis.
show: false,
// Split number of minor ticks. The value should be in range of (0, 100)
splitNumber: 5,
// Length of minor tick
length: 3,
// Line style
lineStyle: {
// Default to be same with axisTick
}
},
minorSplitLine: {
show: false,
lineStyle: {
color: tokens.color.axisMinorSplitLine,
width: 1
}
}
}, defaultOption);
var timeAxis = zrUtil.merge({
splitNumber: 6,
axisLabel: {
// The default value of TimeScale is determined in `AxisBuilder`
// showMinLabel: false,
// showMaxLabel: false,
rich: {
primary: {
fontWeight: 'bold'
}
}
},
splitLine: {
show: false
}
}, valueAxis);
var logAxis = zrUtil.defaults({
logBase: 10
}, valueAxis);
export default {
category: categoryAxis,
value: valueAxis,
time: timeAxis,
log: logAxis
};
+284
View File
@@ -0,0 +1,284 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import OrdinalScale from '../scale/Ordinal.js';
import IntervalScale from '../scale/Interval.js';
import Scale from '../scale/Scale.js';
import TimeScale from '../scale/Time.js';
import LogScale from '../scale/Log.js';
import { AXIS_TYPES } from './axisCommonTypes.js';
import { getStackedDimension } from '../data/helper/dataStackHelper.js';
import { parseTimeAxisLabelFormatter } from '../util/time.js';
import { getScaleBreakHelper } from '../scale/break.js';
import { error } from '../util/log.js';
import { extentDiffers, isLogScale, isOrdinalScale } from '../scale/helper.js';
import { initExtentForUnion, isValidBoundsForExtent, makeInner } from '../util/model.js';
import { getScaleExtentForMappingUnsafe, SCALE_EXTENT_KIND_EFFECTIVE, SCALE_MAPPER_DEPTH_OUT_OF_BREAK } from '../scale/scaleMapper.js';
import ComponentModel from '../model/Component.js';
var axisInner = makeInner();
export function determineAxisType(model) {
var type = model.get('type');
if (
// In ec option, `xxxAxis.type` may be undefined.
type == null
// PENDING: Theoretically, a customized `Scale` is probably impossible, since
// the interface of `Scale` does not guarantee stability. But we still literally
// support it for backward compat, though type incorrect.
|| !zrUtil.hasOwn(AXIS_TYPES, type) && !Scale.getClass(type)) {
type = 'value';
}
return type;
}
export function createScaleByModel(model, type, coordSysSupportAxisBreaks) {
var breakHelper = getScaleBreakHelper();
var breakOption;
if (breakHelper) {
breakOption = retrieveAxisBreaksOption(model, type, coordSysSupportAxisBreaks);
}
switch (type) {
case 'category':
return new OrdinalScale({
ordinalMeta: model.getOrdinalMeta ? model.getOrdinalMeta() : model.getCategories(),
extent: initExtentForUnion()
});
case 'time':
return new TimeScale({
locale: model.ecModel.getLocaleModel(),
useUTC: model.ecModel.get('useUTC'),
breakOption: breakOption
});
case 'log':
// See also #3749
return new LogScale({
logBase: model.get('logBase'),
breakOption: breakOption
});
case 'value':
return new IntervalScale({
breakOption: breakOption
});
default:
// case others.
return new (Scale.getClass(type) || IntervalScale)({});
}
}
/**
* Check if the axis cross a specific value.
*/
export function getScaleValuePositionKind(scale, value, considerMappingExtent) {
var dataExtent = considerMappingExtent ? getScaleExtentForMappingUnsafe(scale, null) : scale.getExtentUnsafe(SCALE_EXTENT_KIND_EFFECTIVE, null);
var min = dataExtent[0];
var max = dataExtent[1];
return !isValidBoundsForExtent(min, max) ? SCALE_VALUE_POSITION_KIND_OUTSIDE : min === value || max === value ? SCALE_VALUE_POSITION_KIND_EDGE : min < value && max > value ? SCALE_VALUE_POSITION_KIND_INSIDE : SCALE_VALUE_POSITION_KIND_OUTSIDE;
}
export var SCALE_VALUE_POSITION_KIND_INSIDE = 1;
export var SCALE_VALUE_POSITION_KIND_EDGE = 2;
export var SCALE_VALUE_POSITION_KIND_OUTSIDE = 3;
export function discourageOnAxisZero(axis) {
axisInner(axis).noOnMyZero = true;
}
/**
* `true`: Prevent orthoganal axes from positioning at the zero point of this axis.
*/
export function isOnAxisZeroDiscouraged(axis) {
return axisInner(axis).noOnMyZero;
}
/**
* @param axis
* @return Label formatter function.
* param: {number} tickValue,
* param: {number} idx, the index in all ticks.
* If category axis, this param is not required.
* return: {string} label string.
*/
export function makeLabelFormatter(axis) {
var labelFormatter = axis.getLabelModel().get('formatter');
if (axis.type === 'time') {
var parsed_1 = parseTimeAxisLabelFormatter(labelFormatter);
return function (tick, idx) {
return axis.scale.getFormattedLabel(tick, idx, parsed_1);
};
} else if (zrUtil.isString(labelFormatter)) {
return function (tick) {
// For category axis, get raw value; for numeric axis,
// get formatted label like '1,333,444'.
var label = axis.scale.getLabel(tick);
var text = labelFormatter.replace('{value}', label != null ? label : '');
return text;
};
} else if (zrUtil.isFunction(labelFormatter)) {
if (axis.type === 'category') {
return function (tick, idx) {
// The original intention of `idx` is "the index of the tick in all ticks".
// But the previous implementation of category axis do not consider the
// `axisLabel.interval`, which cause that, for example, the `interval` is
// `1`, then the ticks "name5", "name7", "name9" are displayed, where the
// corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep
// the definition here for back compatibility.
return labelFormatter(getAxisRawValue(axis, tick), tick.value - axis.scale.getExtent()[0], null // Using `null` just for backward compat.
);
};
}
var scaleBreakHelper_1 = getScaleBreakHelper();
return function (tick, idx) {
// Using `null` just for backward compat. It's been found that in the `test/axis-customTicks.html`,
// there is a formatter `function (value, index, revers = true) { ... }`. Although the third param
// `revers` is incorrect and always `null`, changing it might introduce a breaking change.
var extra = null;
if (scaleBreakHelper_1) {
extra = scaleBreakHelper_1.makeAxisLabelFormatterParamBreak(extra, tick["break"]);
}
return labelFormatter(getAxisRawValue(axis, tick), idx, extra);
};
} else {
return function (tick) {
return axis.scale.getLabel(tick);
};
}
}
export function getAxisRawValue(axis, tick) {
// In category axis with data zoom, tick is not the original
// index of axis.data. So tick should not be exposed to user
// in category axis.
var scale = axis.scale;
return isOrdinalScale(scale) ? scale.getLabel(tick) : tick.value;
}
/**
* @param model axisLabelModel or axisTickModel
*/
export function getOptionCategoryInterval(model) {
var interval = model.get('interval');
return interval == null ? 'auto' : interval;
}
/**
* Set `categoryInterval` as 0 implicitly indicates that
* show all labels regardless of overlap.
* @param {Object} axis axisModel.axis
*/
export function shouldShowAllLabels(axis) {
return axis.type === 'category' && getOptionCategoryInterval(axis.getLabelModel()) === 0;
}
export function getDataDimensionsOnAxis(data, axisDim) {
// Remove duplicated dat dimensions caused by `getStackedDimension`.
var dataDimMap = {};
// Currently `mapDimensionsAll` will contain stack result dimension ('__\0ecstackresult').
// PENDING: is it reasonable? Do we need to remove the original dim from "coord dim" since
// there has been stacked result dim?
zrUtil.each(data.mapDimensionsAll(axisDim), function (dataDim) {
// For example, the extent of the original dimension
// is [0.1, 0.5], the extent of the `stackResultDimension`
// is [7, 9], the final extent should NOT include [0.1, 0.5],
// because there is no graphic corresponding to [0.1, 0.5].
// See the case in `test/area-stack.html` `main1`, where area line
// stack needs `yAxis` not start from 0.
dataDimMap[getStackedDimension(data, dataDim)] = true;
});
return zrUtil.keys(dataDimMap);
}
export function isNameLocationCenter(nameLocation) {
return nameLocation === 'middle' || nameLocation === 'center';
}
export function shouldAxisShow(axisModel) {
return axisModel.getShallow('show');
}
export function retrieveAxisBreaksOption(model, axisType, coordSysSupportAxisBreaks) {
var option = model.get('breaks', true);
if (option != null) {
if (!getScaleBreakHelper()) {
if (process.env.NODE_ENV !== 'production') {
error('Must `import {AxisBreak} from "echarts/features.js"; use(AxisBreak);` first if using breaks option.');
}
return undefined;
}
if (!coordSysSupportAxisBreaks || !isAxisTypeSupportAxisBreak(axisType)) {
if (process.env.NODE_ENV !== 'production') {
// Users have provided `breaks` in ec option but not supported.
var axisInfo = model instanceof ComponentModel ? " " + model.type + "[" + model.componentIndex + "]" : '';
error("Axis" + axisInfo + " does not support break.");
}
return undefined;
}
return option;
}
}
function isAxisTypeSupportAxisBreak(axisType) {
return axisType !== 'category';
}
export function updateIntervalOrLogScaleForNiceOrAligned(scale, fixMinMax, oldIntervalExtent, newIntervalExtent, oldOutermostExtent, cfg) {
var isTargetLogScale = isLogScale(scale);
var intervalStub = isTargetLogScale ? scale.intervalStub : scale;
intervalStub.setExtent(newIntervalExtent[0], newIntervalExtent[1]);
if (isTargetLogScale) {
// Sync intervalStub extent to the outermost extent (i.e., `powStub` for `LogScale`).
var powStub = scale.powStub;
var opt = {
depth: SCALE_MAPPER_DEPTH_OUT_OF_BREAK
};
var minPow = scale.transformOut(newIntervalExtent[0], opt);
var maxPow = scale.transformOut(newIntervalExtent[1], opt);
// Log transform is probably not inversible by rounding error, which causes min/max tick may be
// displayed as `5.999999999999999` unexpectedly when min/max are required to be fixed (specified
// by users or by dataZoom). Therefore we set `powStub` with respect to `oldOutermostExtent` if
// interval extent is not changed. But `intervalStub` should not be inversely changed by this
// handling, otherwise its monotonicity between `niceExtent` and `extent` may be broken and cause
// unexpected ticks generation.
var extentChanged = extentDiffers(oldIntervalExtent, newIntervalExtent);
// NOTE: extent may still be changed even when min/max are required to be fixed,
// e.g., by `intervalScaleEnsureValidExtent`.
if (fixMinMax[0] && !extentChanged[0]) {
minPow = oldOutermostExtent[0];
}
if (fixMinMax[1] && !extentChanged[1]) {
maxPow = oldOutermostExtent[1];
}
powStub.setExtent(minPow, maxPow);
}
intervalStub.setConfig(cfg);
}
export function getTickValueOutermost(scale, tick) {
return isOrdinalScale(scale) ? scale.getRawOrdinalNumber(tick.value) : tick.value;
}
export function isAxisOnBand(scale, axisModel) {
return isOrdinalScale(scale) && !!axisModel.get('boundaryGap');
}
+59
View File
@@ -0,0 +1,59 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
var AxisModelCommonMixin = /** @class */function () {
function AxisModelCommonMixin() {}
AxisModelCommonMixin.prototype.needIncludeZero = function () {
return !this.option.scale;
};
/**
* Should be implemented by each axis model if necessary.
* @return coordinate system model
*/
AxisModelCommonMixin.prototype.getCoordSysModel = function () {
return;
};
return AxisModelCommonMixin;
}();
export { AxisModelCommonMixin };
+119
View File
@@ -0,0 +1,119 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import axisDefault from './axisDefault.js';
import { getLayoutParams, mergeLayoutParam, fetchLayoutMode } from '../util/layout.js';
import OrdinalMeta from '../data/OrdinalMeta.js';
import { AXIS_TYPES } from './axisCommonTypes.js';
import { each, merge } from 'zrender/lib/core/util.js';
import { getAxisBreakHelper } from '../component/axis/axisBreakHelper.js';
/**
* Generate sub axis model class
* @param axisName 'x' 'y' 'radius' 'angle' 'parallel' ...
*/
export default function axisModelCreator(registers, axisName, BaseAxisModelClass, extraDefaultOption) {
each(AXIS_TYPES, function (v, axisType) {
var defaultOption = merge(merge({}, axisDefault[axisType], true), extraDefaultOption, true);
var AxisModel = /** @class */function (_super) {
__extends(AxisModel, _super);
function AxisModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = axisName + 'Axis.' + axisType;
return _this;
}
AxisModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
var layoutMode = fetchLayoutMode(this);
var inputPositionParams = layoutMode ? getLayoutParams(option) : {};
var themeModel = ecModel.getTheme();
merge(option, themeModel.get(axisType + 'Axis'));
merge(option, this.getDefaultOption());
option.type = getAxisType(option);
if (layoutMode) {
mergeLayoutParam(option, inputPositionParams, layoutMode);
}
};
AxisModel.prototype.optionUpdated = function () {
var thisOption = this.option;
if (thisOption.type === 'category') {
this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);
}
};
/**
* Should not be called before all of 'getInitailData' finished.
* Because categories are collected during initializing data.
*/
AxisModel.prototype.getCategories = function (rawData) {
var option = this.option;
// FIXME
// warning if called before all of 'getInitailData' finished.
if (option.type === 'category') {
if (rawData) {
// NOTICE: return the raw data even if not existing; never use a fallback like `[]`;
// Its existence matters in some legacy cases.
return option.data;
}
return this.__ordinalMeta.categories;
}
};
AxisModel.prototype.getOrdinalMeta = function () {
return this.__ordinalMeta;
};
AxisModel.prototype.updateAxisBreaks = function (payload) {
var axisBreakHelper = getAxisBreakHelper();
return axisBreakHelper ? axisBreakHelper.updateModelAxisBreak(this, payload) : {
breaks: []
};
};
AxisModel.type = axisName + 'Axis.' + axisType;
AxisModel.defaultOption = defaultOption;
return AxisModel;
}(BaseAxisModelClass);
registers.registerComponentModel(AxisModel);
});
registers.registerSubTypeDefaulter(axisName + 'Axis', getAxisType);
}
function getAxisType(option) {
// Default axis with data is category axis
return option.type || (option.data ? 'category' : 'value');
}
+204
View File
@@ -0,0 +1,204 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { assert, noop } from 'zrender/lib/core/util.js';
import { ensureValidSplitNumber, getIntervalPrecision, intervalScaleEnsureValidExtent, isIntervalScale, isLogScale, isTimeScale } from '../scale/helper.js';
import { mathCeil, mathFloor, mathMax, nice, quantity, round } from '../util/number.js';
import { updateIntervalOrLogScaleForNiceOrAligned } from './axisHelper.js';
import { calcNiceForTimeScale } from '../scale/Time.js';
import { adoptScaleExtentKindMapping, adoptScaleRawExtentInfoAndPrepare } from './scaleRawExtentInfo.js';
import { getScaleLinearSpanEffective } from '../scale/scaleMapper.js';
// ------ START: LinearIntervalScaleStub Nice ------
function calcNiceForIntervalOrLogScale(scale, opt) {
// [CAVEAT]: If updating this impl, need to sync it to `axisAlignTicks.ts`.
var isTargetLogScale = isLogScale(scale);
var intervalStub = isTargetLogScale ? scale.intervalStub : scale;
var fixMinMax = opt.fixMinMax || [];
var oldOutermostExtent = isTargetLogScale ? scale.getExtent() : null;
var oldIntervalExtent = intervalStub.getExtent();
var newIntervalExtent = intervalScaleEnsureValidExtent(oldIntervalExtent, fixMinMax, opt.rawExtentResult);
intervalStub.setExtent(newIntervalExtent[0], newIntervalExtent[1]);
newIntervalExtent = intervalStub.getExtent();
var config = isTargetLogScale ? logScaleCalcNiceTicks(intervalStub, opt) : intervalScaleCalcNiceTicks(intervalStub, opt);
var autoIntervalPrecision = config.intervalPrecision;
var autoInterval = config.interval;
// When auto calculated interval is not preferable, users are allowed to explicity specify
// `interval`, `min`, `max` to customize the axis. A typical case is, in angle axis with angle
// 0 - 360, where the internally calculated interval is not 60-based.
// NOTICE:
// - In `xxxAxis.type: 'log'`, ec option `xxxAxis.interval` requires a logarithm-applied
// value rather than a value in the raw scale.
// - Follow the historical behavior:
// - even `interval` is specified, the scale extent is still expanded based on the auto-calculated
// interval.
// - No validation to the specified `interval`.
var userInterval = opt.userInterval;
if (userInterval != null) {
config.interval = userInterval;
config.intervalPrecision = getIntervalPrecision(userInterval);
}
if (!fixMinMax[0]) {
newIntervalExtent[0] = round(mathFloor(newIntervalExtent[0] / autoInterval) * autoInterval, autoIntervalPrecision);
}
if (!fixMinMax[1]) {
newIntervalExtent[1] = round(mathCeil(newIntervalExtent[1] / autoInterval) * autoInterval, autoIntervalPrecision);
}
if (userInterval != null) {
// Historical behavior.
config.niceExtent = newIntervalExtent.slice();
}
updateIntervalOrLogScaleForNiceOrAligned(scale, fixMinMax, oldIntervalExtent, newIntervalExtent, oldOutermostExtent, config);
}
// ------ END: LinearIntervalScaleStub Nice ------
// ------ START: IntervalScale Nice ------
function intervalScaleCalcNiceTicks(scale, opt) {
var splitNumber = ensureValidSplitNumber(opt.splitNumber, 5);
// Use the span in the innermost linear space to calculate nice ticks.
var span = getScaleLinearSpanEffective(scale);
if (process.env.NODE_ENV !== 'production') {
assert(isFinite(span) && span > 0); // It should have been ensured by `intervalScaleEnsureValidExtent`.
}
var minInterval = opt.minInterval;
var maxInterval = opt.maxInterval;
var interval = nice(span / splitNumber, true);
if (minInterval != null && interval < minInterval) {
interval = minInterval;
}
if (maxInterval != null && interval > maxInterval) {
interval = maxInterval;
}
var intervalPrecision = getIntervalPrecision(interval);
var extent = scale.getExtent();
// By design, the `niceExtent` is inside the original extent
var niceExtent = [round(mathCeil(extent[0] / interval) * interval, intervalPrecision), round(mathFloor(extent[1] / interval) * interval, intervalPrecision)];
return {
interval: interval,
intervalPrecision: intervalPrecision,
niceExtent: niceExtent
};
}
;
// ------ END: IntervalScale Nice ------
// ------ START: LogScale Nice ------
function logScaleCalcNiceTicks(intervalStub, opt) {
// [CAVEAT]: If updating this impl, need to sync it to `axisAlignTicks.ts`.
var splitNumber = ensureValidSplitNumber(opt.splitNumber, 10);
// Find nice ticks in the "logarithmic space". Notice that "logarithmic space" is a middle space
// rather than the innermost linear space when axis breaks exist.
var intervalExtent = intervalStub.getExtent();
// But use the span in the innermost linear space to calculate nice ticks.
var span = getScaleLinearSpanEffective(intervalStub);
if (process.env.NODE_ENV !== 'production') {
assert(isFinite(span) && span > 0); // It should be ensured by `intervalScaleEnsureValidExtent`.
}
// Interval should be integer
var interval = mathMax(quantity(span), 1);
var err = splitNumber / span * interval;
// Filter ticks to get closer to the desired count.
if (err <= 0.5) {
// TODO: support other bases other than 10?
interval *= 10;
}
var intervalPrecision = getIntervalPrecision(interval);
// For LogScale, we use a `niceExtent` in the "logarithmic space" rather than
// the original "pow space", because it is used in `intervalStub.getTicks()` thereafter.
var niceExtent = [round(mathCeil(intervalExtent[0] / interval) * interval, intervalPrecision), round(mathFloor(intervalExtent[1] / interval) * interval, intervalPrecision)];
return {
intervalPrecision: intervalPrecision,
interval: interval,
niceExtent: niceExtent
};
}
;
/**
* NOTE: See the summary of the process of extent determination in the comment of `scaleMapper.setExtent`.
*
* Calculate a "nice" extent and "nice" ticks configs based on the current scale extent and ec options.
* scale extent will be modified, and config may be set to the scale.
*
* @see SCALE_EXTENT_CONSTRUCTION for the full processing flow.
*/
export function scaleCalcNice(axisLike) {
var scale = axisLike.scale;
var model = axisLike.model;
var axis = model.axis;
var ecModel = model.ecModel;
if (process.env.NODE_ENV !== 'production') {
assert(axis && ecModel);
}
scaleCalcNice2(scale, model, axis, ecModel, null);
}
/**
* @see SCALE_EXTENT_CONSTRUCTION for the full processing flow.
*/
export function scaleCalcNice2(scale, model,
// Some call from external source, such as echarts-gl, may have no `axis` and `ecModel`,
// but has `externalDataExtent`.
axis, ecModel, externalDataExtent) {
var rawExtentResult = adoptScaleRawExtentInfoAndPrepare(scale, model, ecModel, axis, externalDataExtent);
var isIntervalOrTime = isIntervalScale(scale) || isTimeScale(scale);
scaleCalcNiceDirectly(scale, {
splitNumber: model.get('splitNumber'),
fixMinMax: rawExtentResult.fixMM,
userInterval: model.get('interval'),
minInterval: isIntervalOrTime ? model.get('minInterval') : null,
maxInterval: isIntervalOrTime ? model.get('maxInterval') : null,
rawExtentResult: rawExtentResult
});
if (axis && ecModel) {
adoptScaleExtentKindMapping(axis, scale, rawExtentResult, ecModel);
}
if (process.env.NODE_ENV !== 'production') {
scale.freeze();
}
}
export function scaleCalcNiceDirectly(scale, opt) {
scaleCalcNiceMethods[scale.type](scale, opt);
}
var scaleCalcNiceMethods = {
interval: calcNiceForIntervalOrLogScale,
log: calcNiceForIntervalOrLogScale,
time: calcNiceForTimeScale,
ordinal: noop
};
// ------ END: scaleCalcNice Entry ------
+317
View File
@@ -0,0 +1,317 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { assert, createHashMap, each, retrieve2 } from 'zrender/lib/core/util.js';
import { makeCallOnlyOnce, makeInner } from '../util/model.js';
import { getCachePerECFullUpdate, getCachePerECPrepare } from '../util/cycleCache.js';
var callOnlyOnce = makeCallOnlyOnce();
// Ensure that it never appears in internal generated uid and pre-defined coordSysType.
export var AXIS_STAT_KEY_DELIMITER = '|&';
var ecModelCacheFullUpdateInner = makeInner();
// In this case, there are one or multiple valid data value but all the same.
export var LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE = -2;
export var LINEAR_POSITIVE_MIN_GAP_NO_VALID_VALUE = -1;
var ecModelCachePrepareInner = makeInner();
var validateInputAxis;
if (process.env.NODE_ENV !== 'production') {
validateInputAxis = function (axis) {
assert(axis && axis.model && axis.model.uid && axis.model.ecModel);
};
}
function getAxisStatPerKeyPerAxis(axis, axisStatKey) {
var axisModel = axis.model;
var keyed = ecModelCacheFullUpdateInner(getCachePerECFullUpdate(axisModel.ecModel)).keyed;
var perKey = keyed && keyed.get(axisStatKey);
return perKey && perKey.get(axisModel.uid);
}
export function getAxisStat(axis, axisStatKey
// Return: Never return null/undefined.
) {
if (process.env.NODE_ENV !== 'production') {
assert(axisStatKey != null);
validateInputAxis(axis);
}
return wrapStatResult(getAxisStatPerKeyPerAxis(axis, axisStatKey));
}
export function getAxisStatBySeries(axis, seriesList
// Return: Never be null/undefined; never contain null/undefined.
) {
if (process.env.NODE_ENV !== 'production') {
validateInputAxis(axis);
}
var result = [];
eachKeyEachAxis(axis.model.ecModel, function (perKeyPerAxis) {
for (var idx = 0; idx < seriesList.length; idx++) {
if (seriesList[idx] && perKeyPerAxis.serByIdx[seriesList[idx].seriesIndex]) {
result.push(wrapStatResult(perKeyPerAxis));
}
}
});
return result;
}
function eachKeyEachAxis(ecModel, cb) {
var keyed = ecModelCacheFullUpdateInner(getCachePerECFullUpdate(ecModel)).keyed;
keyed && keyed.each(function (perKey, axisStatKey) {
perKey.each(function (perKeyPerAxis, axisModelUid) {
cb(perKeyPerAxis, axisStatKey, axisModelUid);
});
});
}
function wrapStatResult(record) {
return {
liPosMinGap: record ? record.liPosMinGap : undefined
};
}
export function eachSeriesOnAxis(axis, cb) {
if (process.env.NODE_ENV !== 'production') {
validateInputAxis(axis);
}
var ecModel = axis.model.ecModel;
var seriesOnAxisMap = ecModelCacheFullUpdateInner(getCachePerECFullUpdate(ecModel)).axSer;
seriesOnAxisMap && eachSeriesDealForAxisStat(ecModel, seriesOnAxisMap.get(axis.model.uid), cb);
}
/**
* NOTE:
* - series declaration order is respected (some ec option precedence matters, e.g., bar series).
* - series filtered out are excluded.
*/
export function eachSeriesOnAxisOnKey(axis, axisStatKey, cb) {
if (process.env.NODE_ENV !== 'production') {
assert(axisStatKey != null);
validateInputAxis(axis);
}
var perKeyPerAxis = getAxisStatPerKeyPerAxis(axis, axisStatKey);
perKeyPerAxis && eachSeriesDealForAxisStat(axis.model.ecModel, perKeyPerAxis.sers, cb);
}
export function eachSeriesDealForAxisStat(ecModel, seriesList, cb) {
if (!seriesList) {
return;
}
for (var i = 0; i < seriesList.length; i++) {
var seriesModel = seriesList[i];
// Legend-filtered series need to be ignored since series are registered before `legendFilter`.
if (!ecModel.isSeriesFiltered(seriesModel)) {
cb(seriesModel);
}
}
}
/**
* NOTE:
* - series filtered out are excluded.
*/
export function countSeriesOnAxisOnKey(axis, axisStatKey) {
if (process.env.NODE_ENV !== 'production') {
assert(axisStatKey != null);
validateInputAxis(axis);
}
var perKeyPerAxis = getAxisStatPerKeyPerAxis(axis, axisStatKey);
if (!perKeyPerAxis || !perKeyPerAxis.sers.length) {
return 0;
}
var count = 0;
eachSeriesDealForAxisStat(axis.model.ecModel, perKeyPerAxis.sers, function () {
count++;
});
return count;
}
/**
* NOTICE: Available after `CoordinateSystem['create']` (not included).
*
* Query all axes that have at least one associated series (via `associateSeriesWithAxis`)
* by the given key.
*/
export function eachAxisOnKey(ecModel, axisStatKey, cb) {
if (process.env.NODE_ENV !== 'production') {
assert(axisStatKey != null);
}
var keyed = ecModelCacheFullUpdateInner(getCachePerECFullUpdate(ecModel)).keyed;
var perKey = keyed && keyed.get(axisStatKey);
perKey && perKey.each(function (perKeyPerAxis) {
if (process.env.NODE_ENV !== 'production') {
assert(perKeyPerAxis.sers.length > 0); // This is to avoid irrelevant axes to enter `cb`.
}
cb(perKeyPerAxis.axis);
});
}
/**
* NOTICE: Available after `CoordinateSystem['create']` (not included).
*
* Query all `AxisStatKey`s that have at least one associated series (via `associateSeriesWithAxis`)
* by the given axis.
*/
export function eachKeyOnAxis(axis, cb) {
if (process.env.NODE_ENV !== 'production') {
validateInputAxis(axis);
}
var model = axis.model;
var keysByAxisModelUid = ecModelCacheFullUpdateInner(getCachePerECFullUpdate(model.ecModel)).keys;
keysByAxisModelUid && each(keysByAxisModelUid.get(model.uid), function (axisStatKey) {
if (process.env.NODE_ENV !== 'production') {
var stat = getAxisStatPerKeyPerAxis(axis, axisStatKey);
assert(stat && stat.sers.length > 0); // This is to avoid irrelevant `AxisStatKey` to enter `cb`.
}
cb(axisStatKey);
});
}
/**
* NOTICE: this processor may be omitted - it is registered only if required.
*/
function performAxisStatisticsOnOverallReset(ecModel) {
var ecPrepareCache = ecModelCachePrepareInner(getCachePerECPrepare(ecModel));
var ecPrepareCacheKeyed = ecPrepareCache.keyed || (ecPrepareCache.keyed = createHashMap());
eachKeyEachAxis(ecModel, function (perKeyPerAxis, axisStatKey, axisModelUid) {
var ecPrepareCachePerKey = ecPrepareCacheKeyed.get(axisStatKey) || ecPrepareCacheKeyed.set(axisStatKey, createHashMap());
var ecPreparePerKeyPerAxis = ecPrepareCachePerKey.get(axisModelUid) || ecPrepareCachePerKey.set(axisModelUid, {});
if (perKeyPerAxis.metrics.liPosMinGap) {
// We should assert the impl exists -- fail-fast if missing `registerMetricImpl`.
_metricImpl.liPosMinGap(ecModel, perKeyPerAxis, ecPreparePerKeyPerAxis);
}
});
}
// To reduce code size from unnecessary metrics.
export function registerMetricImpl(metricType, impl) {
_metricImpl[metricType] = impl;
}
var _metricImpl = {};
/**
* NOTICE:
* - It must be called in `CoordinateSystem['create']`, before series filtering.
* - It must be called in `seriesIndex` ascending order (series declaration order).
* i.e., iterated by `ecModel.eachSeries`.
* - Every <axis, series> pair can only call this method once.
*
* @see scaleRawExtentInfoCreate in `scaleRawExtentInfo.ts`
*/
export function associateSeriesWithAxis(axis, seriesModel, coordSysType) {
if (!axis) {
return;
}
var ecModel = seriesModel.ecModel;
var ecFullUpdateCache = ecModelCacheFullUpdateInner(getCachePerECFullUpdate(ecModel));
var axisModelUid = axis.model.uid;
if (process.env.NODE_ENV !== 'production') {
validateInputAxis(axis);
// - An axis can be associated with multiple `axisStatKey`s. For example, if `axisStatKey`s are
// "candlestick" and "bar", they can be associated with the same "xAxis".
// - Within an individual axis, it is a typically incorrect usage if a <axis, series> pair is
// associated with multiple `perKeyPerAxis`, which may cause repeated calculation and
// performance degradation, had hard to be found without the checking below. For example, If
// `axisStatKey` are "grid-bar" (see `barGrid.ts`) and "polar-bar" (see `barPolar.ts`), and
// a <xAxis-series> pair is wrongly associated with both "polar-bar" and "grid-bar", the
// relevant statistics will be computed twice.
var axSerPairCheck = ecFullUpdateCache.axSerPairCheck || (ecFullUpdateCache.axSerPairCheck = createHashMap());
var pairKey = "" + axisModelUid + AXIS_STAT_KEY_DELIMITER + seriesModel.uid;
assert(!axSerPairCheck.get(pairKey));
axSerPairCheck.set(pairKey, 1);
}
var seriesOnAxisMap = ecFullUpdateCache.axSer || (ecFullUpdateCache.axSer = createHashMap());
var seriesListPerAxis = seriesOnAxisMap.get(axisModelUid) || seriesOnAxisMap.set(axisModelUid, []);
if (process.env.NODE_ENV !== 'production') {
var lastSeries = seriesListPerAxis[seriesListPerAxis.length - 1];
if (lastSeries) {
// Series order should respect to the input order, since it matters in some cases
// (e.g., see `barGrid.ts` and `barPolar.ts` - ec option declaration order matters).
assert(lastSeries.seriesIndex < seriesModel.seriesIndex);
}
}
seriesListPerAxis.push(seriesModel);
var seriesType = seriesModel.subType;
var isBaseAxis = seriesModel.getBaseAxis() === axis;
var client = clientsForLookup.get(makeClientLookupKey(seriesType, isBaseAxis, coordSysType)) || clientsForLookup.get(makeClientLookupKey(seriesType, isBaseAxis, null));
if (!client) {
return;
}
var keyed = ecFullUpdateCache.keyed || (ecFullUpdateCache.keyed = createHashMap());
var keys = ecFullUpdateCache.keys || (ecFullUpdateCache.keys = createHashMap());
var axisStatKey = client.key;
var perKey = keyed.get(axisStatKey) || keyed.set(axisStatKey, createHashMap());
var perKeyPerAxis = perKey.get(axisModelUid);
if (!perKeyPerAxis) {
perKeyPerAxis = perKey.set(axisModelUid, {
axis: axis,
sers: [],
serByIdx: []
});
// They should only be executed for each <key, axis> pair once:
perKeyPerAxis.metrics = client.getMetrics(axis);
(keys.get(axisModelUid) || keys.set(axisModelUid, [])).push(axisStatKey);
}
// series order should respect to the input order.
perKeyPerAxis.sers.push(seriesModel);
perKeyPerAxis.serByIdx[seriesModel.seriesIndex] = seriesModel;
}
/**
* NOTE: Currently, the scenario is simple enough to look up clients by hash map.
* Otherwise, a caller-provided `filter` may be an alternative if more complex requirements arise.
*/
function makeClientLookupKey(seriesType, isBaseAxis, coordSysType) {
return seriesType + AXIS_STAT_KEY_DELIMITER + retrieve2(isBaseAxis, true) + AXIS_STAT_KEY_DELIMITER + (coordSysType || '');
}
/**
* NOTICE: Can only be called in "install" stage.
*
* See `axisSnippets.ts` for some commonly used clients.
*/
export function requireAxisStatistics(registers, client) {
var clientKey = makeClientLookupKey(client.seriesType, client.baseAxis, client.coordSysType);
if (process.env.NODE_ENV !== 'production') {
assert(client.seriesType && client.key && !clientsForCheckingStatKey.get(client.key) && !clientsForLookup.get(clientKey)); // More checking is performed in `axSerPairCheck`.
clientsForCheckingStatKey.set(client.key, 1);
}
clientsForLookup.set(clientKey, client);
callOnlyOnce(registers, function () {
registers.registerProcessor(registers.PRIORITY.PROCESSOR.AXIS_STATISTICS, {
// NOTE: Theoretically, `appendData` requires `dirtyOnOverallProgress: true` here to re-calculate them.
// But this OVERALL_STAGE_TASK is applied to all series (no `getTargetSeries` specified),
// `dirtyOnOverallProgress: true` can cause irrelevant series (e.g., series on geo)
// to be re-rendered when `appendData` is called, which cause `appendData` meaningless,
// thereby not setting `dirtyOnOverallProgress: true`.
overallReset: performAxisStatisticsOnOverallReset
});
});
}
var clientsForCheckingStatKey;
if (process.env.NODE_ENV !== 'production') {
clientsForCheckingStatKey = createHashMap();
}
var clientsForLookup = createHashMap();
+156
View File
@@ -0,0 +1,156 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { createHashMap } from 'zrender/lib/core/util.js';
import { asc, isNullableNumberFinite } from '../util/number.js';
import { parseSanitizationFilter, passesSanitizationFilter } from '../data/helper/dataValueHelper.js';
import { tryEnsureTypedArray, Float64ArrayCtor } from '../util/vendor.js';
import { eachSeriesDealForAxisStat, LINEAR_POSITIVE_MIN_GAP_NO_VALID_VALUE, LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE, registerMetricImpl } from './axisStatistics.js';
export function registerMetricImplLiPosMinGap() {
registerMetricImpl('liPosMinGap', metricLiPosMinGapImpl);
}
function metricLiPosMinGapImpl(ecModel, perKeyPerAxis, ecPreparePerKeyPerAxis) {
var newSerUids = createHashMap();
var ecPrepareSerUids = ecPreparePerKeyPerAxis.serUids;
var ecPrepareLiPosMinGap = ecPreparePerKeyPerAxis.liPosMinGap;
var ecPrepareCacheMiss;
var axis = perKeyPerAxis.axis;
var scale = axis.scale;
// const linearValueExtent = initExtentForUnion();
var needTransform = scale.needTransform();
var filter = scale.getFilter ? scale.getFilter() : null;
var filterParsed = parseSanitizationFilter(filter);
// const timeRetrieve: number[] = []; // _EC_PERF_
// const timeSort: number[] = []; // _EC_PERF_
// const timeAll: number[] = []; // _EC_PERF_
// timeAll[0] = Date.now(); // _EC_PERF_
function eachSeries(cb) {
eachSeriesDealForAxisStat(ecModel, perKeyPerAxis.sers, function (seriesModel) {
var rawData = seriesModel.getRawData();
// NOTE: Currently there is no series that a "base axis" can map to multiple dimensions.
var dimStoreIdx = rawData.getDimensionIndex(rawData.mapDimension(axis.dim));
if (dimStoreIdx >= 0) {
cb(dimStoreIdx, seriesModel, rawData.getStore());
}
});
}
var bufferCapacity = 0;
eachSeries(function (dimStoreIdx, seriesModel, rawDataStore) {
newSerUids.set(seriesModel.uid, 1);
if (!ecPrepareSerUids || !ecPrepareSerUids.hasKey(seriesModel.uid)) {
ecPrepareCacheMiss = true;
}
bufferCapacity += rawDataStore.count();
});
if (!ecPrepareSerUids || ecPrepareSerUids.keys().length !== newSerUids.keys().length) {
ecPrepareCacheMiss = true;
}
if (!ecPrepareCacheMiss && ecPrepareLiPosMinGap != null) {
// Consider the fact in practice:
// - Series data can only be changed in EC_PREPARE.
// - The relationship between series and axes can only be changed in EC_PREPARE and
// SERIES_FILTER.
// (See EC_CYCLE for more info)
// Therefore, some statistics results can be cached in `GlobalModelCachePerECPrepare` to avoid
// repeated time-consuming calculation for large data (e.g., over 1e5 data items).
perKeyPerAxis.liPosMinGap = ecPrepareLiPosMinGap;
return;
}
tryEnsureTypedArray(tmpValueBuffer, bufferCapacity);
// timeRetrieve[0] = Date.now(); // _EC_PERF_
var writeIdx = 0;
eachSeries(function (dimStoreIdx, seriesModel, store) {
// NOTE: It appears to be optimized by traveling only in a specific window (e.g., the current window)
// instead of the entire data, but that would likely generate inconsistent result and bring
// jitter when dataZoom roaming.
for (var i = 0, cnt = store.count(); i < cnt; ++i) {
// Manually inline some code for performance, since no other optimization
// (such as, progressive) can be applied here.
var val = store.get(dimStoreIdx, i);
// NOTE: in most cases, filter does not exist.
if (isFinite(val) && (!filter || passesSanitizationFilter(filterParsed, val))) {
if (needTransform) {
// PENDING: time-consuming if axis break is applied.
val = scale.transformIn(val, null);
}
tmpValueBuffer.arr[writeIdx++] = val;
// val < linearValueExtent[0] && (linearValueExtent[0] = val);
// val > linearValueExtent[1] && (linearValueExtent[1] = val);
}
}
});
// Indicatively, retrieving values above costs 40ms for 1e6 values in a certain platform.
// timeRetrieve[1] = Date.now(); // _EC_PERF_
var tmpValueBufferView = tmpValueBuffer.typed ? tmpValueBuffer.arr.subarray(0, writeIdx) : (tmpValueBuffer.arr.length = writeIdx, tmpValueBuffer.arr);
// timeSort[0] = Date.now(); // _EC_PERF_
// Sort axis values into ascending order to calculate gaps.
if (tmpValueBuffer.typed) {
// Indicatively, 5ms for 1e6 values in a certain platform.
tmpValueBufferView.sort();
} else {
asc(tmpValueBufferView);
}
// timeAll[1] = timeSort[1] = Date.now(); // _EC_PERF_
// console.log('axisStatistics_minGap_retrieve', timeRetrieve[1] - timeRetrieve[0]); // _EC_PERF_
// console.log('axisStatistics_minGap_sort', timeSort[1] - timeSort[0]); // _EC_PERF_
// console.log('axisStatistics_minGap_all', timeAll[1] - timeAll[0]); // _EC_PERF_
var min = Infinity;
for (var j = 1; j < writeIdx; ++j) {
var delta = tmpValueBufferView[j] - tmpValueBufferView[j - 1];
if (
// - Different series normally have the same values (e.g., barA, barB, barC),
// which should be ignored.
// - A single series with multiple same values is often not meaningful to
// create `bandWidth`, so it is also ignored.
delta > 0 && delta < min) {
min = delta;
}
}
ecPreparePerKeyPerAxis.liPosMinGap = perKeyPerAxis.liPosMinGap = isNullableNumberFinite(min) ? min : writeIdx > 0 ? LINEAR_POSITIVE_MIN_GAP_SINGLE_VALID_VALUE : LINEAR_POSITIVE_MIN_GAP_NO_VALID_VALUE;
ecPreparePerKeyPerAxis.serUids = newSerUids;
}
// For performance optimization.
var tmpValueBuffer = tryEnsureTypedArray({
ctor: Float64ArrayCtor
}, 50 // An arbitrary initial capability.
);
+386
View File
@@ -0,0 +1,386 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import * as textContain from 'zrender/lib/contain/text.js';
import { makeInner, removeDuplicates, removeDuplicatesGetKeyFromItemItself } from '../util/model.js';
import { makeLabelFormatter, getOptionCategoryInterval } from './axisHelper.js';
import { asc } from '../util/number.js';
import { ordinalScaleCreateTicks } from '../scale/helper.js';
var modelInner = makeInner();
var axisInner = makeInner();
export var AxisTickLabelComputingKind = {
estimate: 1,
determine: 2
};
export function createAxisLabelsComputingContext(kind) {
return {
out: {
noPxChangeTryDetermine: []
},
kind: kind
};
}
/**
* CAUTION: Do not modify the result.
*/
export function createAxisLabels(axis, ctx) {
var custom = axis.getLabelModel().get('customValues');
if (custom) {
var scale_1 = axis.scale;
return {
labels: zrUtil.map(parseTickLabelCustomValues(custom, scale_1), function (tick, index) {
return {
formattedLabel: makeLabelFormatter(axis)(tick, index),
rawLabel: scale_1.getLabel(tick),
tick: tick
};
})
};
}
// Only ordinal scale support tick interval
return axis.type === 'category' ? makeCategoryLabels(axis, ctx) : makeRealNumberLabels(axis);
}
/**
* CAUTION: Do not modify the result.
*
* @param tickModel For example, can be axisTick, splitLine, splitArea.
*/
export function createAxisTicks(axis, tickModel, opt) {
var scale = axis.scale;
var custom = axis.getTickModel().get('customValues');
if (custom) {
return {
ticks: parseTickLabelCustomValues(custom, scale)
};
}
// Only ordinal scale support tick interval
return axis.type === 'category' ? makeCategoryTicks(axis, tickModel) : {
ticks: scale.getTicks(opt)
};
}
function parseTickLabelCustomValues(customValues, scale) {
var extent = scale.getExtent();
var tickNumbers = [];
zrUtil.each(customValues, function (val) {
val = scale.parse(val);
if (val >= extent[0] && val <= extent[1]) {
tickNumbers.push(val);
}
});
removeDuplicates(tickNumbers, removeDuplicatesGetKeyFromItemItself, null);
asc(tickNumbers);
return zrUtil.map(tickNumbers, function (tickVal) {
return {
value: tickVal
};
});
}
function makeCategoryLabels(axis, ctx) {
var labelModel = axis.getLabelModel();
var result = makeCategoryLabelsActually(axis, labelModel, ctx);
return !labelModel.get('show') || axis.scale.isBlank() ? {
labels: []
} : result;
}
function makeCategoryLabelsActually(axis, labelModel, ctx) {
var labelsCache = ensureCategoryLabelCache(axis);
var optionLabelInterval = getOptionCategoryInterval(labelModel);
var isEstimate = ctx.kind === AxisTickLabelComputingKind.estimate;
// In AxisTickLabelComputingKind.estimate, the result likely varies during a single
// pass of ec main process,due to the change of axisExtent, and will not be shared with
// splitLine. Therefore no cache is used.
if (!isEstimate) {
// PENDING: check necessary?
var result_1 = axisCacheGet(labelsCache, optionLabelInterval);
if (result_1) {
return result_1;
}
}
var labels;
var numericLabelInterval;
if (zrUtil.isFunction(optionLabelInterval)) {
labels = makeTicksLabelsByCategoryIntervalNumOrCb(axis, optionLabelInterval, false);
} else {
numericLabelInterval = optionLabelInterval === 'auto' ? makeAutoCategoryInterval(axis, ctx) : optionLabelInterval;
labels = makeTicksLabelsByCategoryIntervalNumOrCb(axis, numericLabelInterval, false);
}
var result = {
labels: labels,
labelCategoryInterval: numericLabelInterval
};
if (!isEstimate) {
axisCacheSet(labelsCache, optionLabelInterval, result);
} else {
ctx.out.noPxChangeTryDetermine.push(function () {
axisCacheSet(labelsCache, optionLabelInterval, result);
return true;
});
}
return result;
}
function makeCategoryTicks(axis, tickModel) {
var ticksCache = ensureCategoryTickCache(axis);
var optionTickInterval = getOptionCategoryInterval(tickModel);
var result = axisCacheGet(ticksCache, optionTickInterval);
if (result) {
return result;
}
var ticks;
var tickCategoryInterval;
// Optimize for the case that large category data and no label displayed,
// we should not return all ticks.
if (!tickModel.get('show') || axis.scale.isBlank()) {
ticks = [];
}
if (zrUtil.isFunction(optionTickInterval)) {
ticks = makeTicksLabelsByCategoryIntervalNumOrCb(axis, optionTickInterval, true);
}
// Always use label interval by default despite label show. Consider this
// scenario, Use multiple grid with the xAxis sync, and only one xAxis shows
// labels. `splitLine` and `axisTick` should be consistent in this case.
else if (optionTickInterval === 'auto') {
var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel(), createAxisLabelsComputingContext(AxisTickLabelComputingKind.determine));
tickCategoryInterval = labelsResult.labelCategoryInterval;
ticks = zrUtil.map(labelsResult.labels, function (labelItem) {
return labelItem.tick;
});
} else {
tickCategoryInterval = optionTickInterval;
ticks = makeTicksLabelsByCategoryIntervalNumOrCb(axis, tickCategoryInterval, true);
}
// Cache to avoid calling interval function repeatedly.
return axisCacheSet(ticksCache, optionTickInterval, {
ticks: ticks,
tickCategoryInterval: tickCategoryInterval
});
}
function makeRealNumberLabels(axis) {
var ticks = axis.scale.getTicks();
var labelFormatter = makeLabelFormatter(axis);
return {
labels: zrUtil.map(ticks, function (tick, idx) {
return {
formattedLabel: labelFormatter(tick, idx),
rawLabel: axis.scale.getLabel(tick),
tick: tick
};
})
};
}
// Large category data calculation is performance sensitive, and ticks and label probably will
// be fetched multiple times (e.g. shared by splitLine and axisTick). So we cache the result.
// axis is created each time during a ec process, so we do not need to clear cache.
var ensureCategoryTickCache = initAxisCacheMethod('axisTick');
var ensureCategoryLabelCache = initAxisCacheMethod('axisLabel');
/**
* PENDING: refactor to JS Map? Because key can be a function or more complicated object, and
* cache size always is small, and currently no JS Map object key polyfill, we use a simple
* array cache instead of plain object hash.
*/
function initAxisCacheMethod(prop) {
return function ensureCache(axis) {
return axisInner(axis)[prop] || (axisInner(axis)[prop] = {
list: []
});
};
}
function axisCacheGet(cache, key) {
for (var i = 0; i < cache.list.length; i++) {
if (cache.list[i].key === key) {
return cache.list[i].value;
}
}
}
function axisCacheSet(cache, key, value) {
cache.list.push({
key: key,
value: value
});
return value;
}
function makeAutoCategoryInterval(axis, ctx) {
if (ctx.kind === AxisTickLabelComputingKind.estimate) {
// Currently axisTick is not involved in estimate kind, and the result likely varies during a
// single pass of ec main process, due to the change of axisExtent. Therefore no cache is used.
var result_2 = axis.calculateCategoryInterval(ctx);
ctx.out.noPxChangeTryDetermine.push(function () {
axisInner(axis).autoInterval = result_2;
return true;
});
return result_2;
}
// Both tick and label uses this result, cacah it to avoid recompute.
var result = axisInner(axis).autoInterval;
return result != null ? result : axisInner(axis).autoInterval = axis.calculateCategoryInterval(ctx);
}
/**
* Calculate interval for category axis ticks and labels.
* Use a strategy to try to avoid overlapping.
* To get precise result, at least one of `getRotate` and `isHorizontal`
* should be implemented in axis.
*/
export function calculateCategoryInterval(axis, ctx) {
var kind = ctx.kind;
var params = fetchAutoCategoryIntervalCalculationParams(axis);
var labelFormatter = makeLabelFormatter(axis);
var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;
var ordinalScale = axis.scale;
var ordinalExtent = ordinalScale.getExtent();
// Providing this method is for optimization:
// avoid generating a long array by `getTicks`
// in large category data case.
var tickCount = ordinalScale.count();
if (ordinalExtent[1] - ordinalExtent[0] < 1) {
return 0;
}
var step = 1;
// Simple optimization. Arbitrary value.
var maxCount = 40;
if (tickCount > maxCount) {
step = Math.max(1, Math.floor(tickCount / maxCount));
}
var tickValue = ordinalExtent[0];
var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);
var unitW = Math.abs(unitSpan * Math.cos(rotation));
var unitH = Math.abs(unitSpan * Math.sin(rotation));
var maxW = 0;
var maxH = 0;
// Caution: Performance sensitive for large category data.
// Consider dataZoom, we should make appropriate step to avoid O(n) loop.
for (; tickValue <= ordinalExtent[1]; tickValue += step) {
var width = 0;
var height = 0;
// Not precise, do not consider align and vertical align
// and each distance from axis line yet.
var rect = textContain.getBoundingRect(labelFormatter({
value: tickValue
}), params.font, 'center', 'top');
// Magic number
width = rect.width * 1.3;
height = rect.height * 1.3;
// Min size, void long loop.
maxW = Math.max(maxW, width, 7);
maxH = Math.max(maxH, height, 7);
}
var dw = maxW / unitW;
var dh = maxH / unitH;
// 0/0 is NaN, 1/0 is Infinity.
isNaN(dw) && (dw = Infinity);
isNaN(dh) && (dh = Infinity);
var interval = Math.max(0, Math.floor(Math.min(dw, dh)));
if (kind === AxisTickLabelComputingKind.estimate) {
// In estimate kind, the inteval likely varies, thus do not erase the cache.
ctx.out.noPxChangeTryDetermine.push(zrUtil.bind(calculateCategoryIntervalTryDetermine, null, axis, interval, tickCount));
return interval;
}
var lastInterval = calculateCategoryIntervalDealCache(axis, interval, tickCount);
return lastInterval != null ? lastInterval : interval;
}
function calculateCategoryIntervalTryDetermine(axis, interval, tickCount) {
return calculateCategoryIntervalDealCache(axis, interval, tickCount) == null;
}
// Return the lastInterval if need to use it, otherwise return NullUndefined and save cache.
function calculateCategoryIntervalDealCache(axis, interval, tickCount) {
var cache = modelInner(axis.model);
var axisExtent = axis.getExtent();
var lastAutoInterval = cache.lastAutoInterval;
var lastTickCount = cache.lastTickCount;
// Use cache to keep interval stable while moving zoom window,
// otherwise the calculated interval might jitter when the zoom
// window size is close to the interval-changing size.
// For example, if all of the axis labels are `a, b, c, d, e, f, g`.
// The jitter will cause that sometimes the displayed labels are
// `a, d, g` (interval: 2) sometimes `a, c, e`(interval: 1).
if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1
// Always choose the bigger one, otherwise the critical
// point is not the same when zooming in or zooming out.
&& lastAutoInterval > interval
// If the axis change is caused by chart resize, the cache should not
// be used. Otherwise some hidden labels might not be shown again.
&& cache.axisExtent0 === axisExtent[0] && cache.axisExtent1 === axisExtent[1]) {
return lastAutoInterval;
}
// Only update cache if cache not used, otherwise the
// changing of interval is too insensitive.
else {
cache.lastTickCount = tickCount;
cache.lastAutoInterval = interval;
cache.axisExtent0 = axisExtent[0];
cache.axisExtent1 = axisExtent[1];
}
}
function fetchAutoCategoryIntervalCalculationParams(axis) {
var labelModel = axis.getLabelModel();
return {
axisRotate: axis.getRotate ? axis.getRotate() : axis.isHorizontal && !axis.isHorizontal() ? 90 : 0,
labelRotate: labelModel.get('rotate') || 0,
font: labelModel.getFont()
};
}
function makeTicksLabelsByCategoryIntervalNumOrCb(axis, categoryInterval, onlyTick) {
var labelFormatter = makeLabelFormatter(axis);
var ordinalScale = axis.scale;
var result = [];
var categoryIntervalIsCb = zrUtil.isFunction(categoryInterval);
ordinalScaleCreateTicks(ordinalScale, categoryIntervalIsCb ? 0 : categoryInterval, function (tickObj, isExtentBoundary) {
var tickLabel = ordinalScale.getLabel(tickObj);
if (categoryIntervalIsCb) {
// When interval is function, a falsy return means ignore the tick.
// It is time consuming for large category data.
var isOnInterval = !!categoryInterval(tickObj.value, tickLabel);
tickObj.offInterval = !isOnInterval;
// axis extent min max labels should be always included and the display strategy
// is adopted uniformly later in `AxisBuilder`.
if (!isOnInterval && !isExtentBoundary) {
return;
}
}
result.push(onlyTick ? tickObj : {
formattedLabel: labelFormatter(tickObj),
rawLabel: tickLabel,
tick: tickObj
});
});
return result;
}
+397
View File
@@ -0,0 +1,397 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import * as layout from '../../util/layout.js';
import * as numberUtil from '../../util/number.js';
import BoundingRect from 'zrender/lib/core/BoundingRect.js';
import { expandOrShrinkRect } from '../../util/graphic.js';
import { injectCoordSysByOption, simpleCoordSysInjectionProvider } from '../../core/CoordinateSystem.js';
// (24*60*60*1000)
var PROXIMATE_ONE_DAY = 86400000;
var Calendar = /** @class */function () {
function Calendar(calendarModel, ecModel, api) {
this.type = 'calendar';
this.dimensions = Calendar.dimensions;
// Required in createListFromData
this.getDimensionsInfo = Calendar.getDimensionsInfo;
this._model = calendarModel;
this._update(ecModel, api);
}
Calendar.getDimensionsInfo = function () {
return [{
name: 'time',
type: 'time'
}, 'value'];
};
Calendar.prototype.getRangeInfo = function () {
return this._rangeInfo;
};
Calendar.prototype.getModel = function () {
return this._model;
};
Calendar.prototype.getRect = function () {
return this._rect;
};
Calendar.prototype.getCellWidth = function () {
return this._sw;
};
Calendar.prototype.getCellHeight = function () {
return this._sh;
};
Calendar.prototype.getOrient = function () {
return this._orient;
};
/**
* getFirstDayOfWeek
*
* @example
* 0 : start at Sunday
* 1 : start at Monday
*
* @return {number}
*/
Calendar.prototype.getFirstDayOfWeek = function () {
return this._firstDayOfWeek;
};
/**
* get date info
* }
*/
Calendar.prototype.getDateInfo = function (date) {
date = numberUtil.parseDate(date);
var y = date.getFullYear();
var m = date.getMonth() + 1;
var mStr = m < 10 ? '0' + m : '' + m;
var d = date.getDate();
var dStr = d < 10 ? '0' + d : '' + d;
var day = date.getDay();
day = Math.abs((day + 7 - this.getFirstDayOfWeek()) % 7);
return {
y: y + '',
m: mStr,
d: dStr,
day: day,
time: date.getTime(),
formatedDate: y + '-' + mStr + '-' + dStr,
date: date
};
};
Calendar.prototype.getNextNDay = function (date, n) {
n = n || 0;
if (n === 0) {
return this.getDateInfo(date);
}
date = new Date(this.getDateInfo(date).time);
date.setDate(date.getDate() + n);
return this.getDateInfo(date);
};
Calendar.prototype._update = function (ecModel, api) {
this._firstDayOfWeek = +this._model.getModel('dayLabel').get('firstDay');
this._orient = this._model.get('orient');
this._lineWidth = this._model.getModel('itemStyle').getItemStyle().lineWidth || 0;
this._rangeInfo = this._getRangeInfo(this._initRangeOption());
var weeks = this._rangeInfo.weeks || 1;
var whNames = ['width', 'height'];
var cellSize = this._model.getCellSize().slice();
var layoutParams = this._model.getBoxLayoutParams();
var cellNumbers = this._orient === 'horizontal' ? [weeks, 7] : [7, weeks];
zrUtil.each([0, 1], function (idx) {
if (cellSizeSpecified(cellSize, idx)) {
layoutParams[whNames[idx]] = cellSize[idx] * cellNumbers[idx];
}
});
var whGlobal = {
width: api.getWidth(),
height: api.getHeight()
};
var calendarRect = this._rect = layout.getLayoutRect(layoutParams, whGlobal);
zrUtil.each([0, 1], function (idx) {
if (!cellSizeSpecified(cellSize, idx)) {
cellSize[idx] = calendarRect[whNames[idx]] / cellNumbers[idx];
}
});
function cellSizeSpecified(cellSize, idx) {
return cellSize[idx] != null && cellSize[idx] !== 'auto';
}
// Has been calculated out number.
this._sw = cellSize[0];
this._sh = cellSize[1];
};
/**
* Convert a time data(time, value) item to (x, y) point.
*/
// TODO Clamp of calendar is not same with cartesian coordinate systems.
// It will return NaN if data exceeds.
Calendar.prototype.dataToPoint = function (data, clamp, out) {
out = out || [];
zrUtil.isArray(data) && (data = data[0]);
clamp == null && (clamp = true);
var dayInfo = this.getDateInfo(data);
var range = this._rangeInfo;
var date = dayInfo.formatedDate;
// if not in range return [NaN, NaN]
if (clamp && !(dayInfo.time >= range.start.time && dayInfo.time < range.end.time + PROXIMATE_ONE_DAY)) {
out[0] = out[1] = NaN;
return out;
}
var week = dayInfo.day;
var nthWeek = this._getRangeInfo([range.start.time, date]).nthWeek;
if (this._orient === 'vertical') {
out[0] = this._rect.x + week * this._sw + this._sw / 2;
out[1] = this._rect.y + nthWeek * this._sh + this._sh / 2;
} else {
out[0] = this._rect.x + nthWeek * this._sw + this._sw / 2;
out[1] = this._rect.y + week * this._sh + this._sh / 2;
}
return out;
};
/**
* Convert a (x, y) point to time data
*/
Calendar.prototype.pointToData = function (point) {
var date = this.pointToDate(point);
return date && date.time;
};
Calendar.prototype.dataToLayout = function (data, clamp, out) {
out = out || {};
var rect = out.rect = out.rect || {};
var contentRect = out.contentRect = out.contentRect || {};
var point = this.dataToPoint(data, clamp);
rect.x = point[0] - this._sw / 2;
rect.y = point[1] - this._sh / 2;
rect.width = this._sw;
rect.height = this._sh;
BoundingRect.copy(contentRect, rect);
expandOrShrinkRect(contentRect, this._lineWidth / 2, true, true);
return out;
};
/**
* Convert a time date item to (x, y) four point.
*/
Calendar.prototype.dataToCalendarLayout = function (data, clamp) {
var point = this.dataToPoint(data, clamp);
return {
center: point,
tl: [point[0] - this._sw / 2, point[1] - this._sh / 2],
tr: [point[0] + this._sw / 2, point[1] - this._sh / 2],
br: [point[0] + this._sw / 2, point[1] + this._sh / 2],
bl: [point[0] - this._sw / 2, point[1] + this._sh / 2]
};
};
/**
* Convert a (x, y) point to time date
*
* @param {Array} point point
* @return {Object} date
*/
Calendar.prototype.pointToDate = function (point) {
var nthX = Math.floor((point[0] - this._rect.x) / this._sw) + 1;
var nthY = Math.floor((point[1] - this._rect.y) / this._sh) + 1;
var range = this._rangeInfo.range;
if (this._orient === 'vertical') {
return this._getDateByWeeksAndDay(nthY, nthX - 1, range);
}
return this._getDateByWeeksAndDay(nthX, nthY - 1, range);
};
Calendar.prototype.convertToPixel = function (ecModel, finder, value) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.dataToPoint(value) : null;
};
Calendar.prototype.convertToLayout = function (ecModel, finder, value) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.dataToLayout(value) : null;
};
Calendar.prototype.convertFromPixel = function (ecModel, finder, pixel) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.pointToData(pixel) : null;
};
Calendar.prototype.containPoint = function (point) {
console.warn('Not implemented.');
return false;
};
/**
* initRange
* Normalize to an [start, end] array
*/
Calendar.prototype._initRangeOption = function () {
var range = this._model.get('range');
var normalizedRange;
// Convert [1990] to 1990
if (zrUtil.isArray(range) && range.length === 1) {
range = range[0];
}
if (!zrUtil.isArray(range)) {
var rangeStr = range.toString();
// One year.
if (/^\d{4}$/.test(rangeStr)) {
normalizedRange = [rangeStr + '-01-01', rangeStr + '-12-31'];
}
// One month
if (/^\d{4}[\/|-]\d{1,2}$/.test(rangeStr)) {
var start = this.getDateInfo(rangeStr);
var firstDay = start.date;
firstDay.setMonth(firstDay.getMonth() + 1);
var end = this.getNextNDay(firstDay, -1);
normalizedRange = [start.formatedDate, end.formatedDate];
}
// One day
if (/^\d{4}[\/|-]\d{1,2}[\/|-]\d{1,2}$/.test(rangeStr)) {
normalizedRange = [rangeStr, rangeStr];
}
} else {
normalizedRange = range;
}
if (!normalizedRange) {
if (process.env.NODE_ENV !== 'production') {
zrUtil.logError('Invalid date range.');
}
// Not handling it.
return range;
}
var tmp = this._getRangeInfo(normalizedRange);
if (tmp.start.time > tmp.end.time) {
normalizedRange.reverse();
}
return normalizedRange;
};
/**
* range info
*
* @private
* @param {Array} range range ['2017-01-01', '2017-07-08']
* If range[0] > range[1], they will not be reversed.
* @return {Object} obj
*/
Calendar.prototype._getRangeInfo = function (range) {
var parsedRange = [this.getDateInfo(range[0]), this.getDateInfo(range[1])];
var reversed;
if (parsedRange[0].time > parsedRange[1].time) {
reversed = true;
parsedRange.reverse();
}
var allDay = Math.floor(parsedRange[1].time / PROXIMATE_ONE_DAY) - Math.floor(parsedRange[0].time / PROXIMATE_ONE_DAY) + 1;
// Consider case1 (#11677 #10430):
// Set the system timezone as "UK", set the range to `['2016-07-01', '2016-12-31']`
// Consider case2:
// Firstly set system timezone as "Time Zone: America/Toronto",
// ```
// let first = new Date(1478412000000 - 3600 * 1000 * 2.5);
// let second = new Date(1478412000000);
// let allDays = Math.floor(second / ONE_DAY) - Math.floor(first / ONE_DAY) + 1;
// ```
// will get wrong result because of DST. So we should fix it.
var date = new Date(parsedRange[0].time);
var startDateNum = date.getDate();
var endDateNum = parsedRange[1].date.getDate();
date.setDate(startDateNum + allDay - 1);
// The bias can not over a month, so just compare date.
var dateNum = date.getDate();
if (dateNum !== endDateNum) {
var sign = date.getTime() - parsedRange[1].time > 0 ? 1 : -1;
while ((dateNum = date.getDate()) !== endDateNum && (date.getTime() - parsedRange[1].time) * sign > 0) {
allDay -= sign;
date.setDate(dateNum - sign);
}
}
var weeks = Math.floor((allDay + parsedRange[0].day + 6) / 7);
var nthWeek = reversed ? -weeks + 1 : weeks - 1;
reversed && parsedRange.reverse();
return {
range: [parsedRange[0].formatedDate, parsedRange[1].formatedDate],
start: parsedRange[0],
end: parsedRange[1],
allDay: allDay,
weeks: weeks,
// From 0.
nthWeek: nthWeek,
fweek: parsedRange[0].day,
lweek: parsedRange[1].day
};
};
/**
* get date by nthWeeks and week day in range
*
* @private
* @param {number} nthWeek the week
* @param {number} day the week day
* @param {Array} range [d1, d2]
* @return {Object}
*/
Calendar.prototype._getDateByWeeksAndDay = function (nthWeek, day, range) {
var rangeInfo = this._getRangeInfo(range);
if (nthWeek > rangeInfo.weeks || nthWeek === 0 && day < rangeInfo.fweek || nthWeek === rangeInfo.weeks && day > rangeInfo.lweek) {
return null;
}
var nthDay = (nthWeek - 1) * 7 - rangeInfo.fweek + day;
var date = new Date(rangeInfo.start.time);
date.setDate(+rangeInfo.start.d + nthDay);
return this.getDateInfo(date);
};
Calendar.create = function (ecModel, api) {
var calendarList = [];
ecModel.eachComponent('calendar', function (calendarModel) {
var calendar = new Calendar(calendarModel, ecModel, api);
calendarList.push(calendar);
calendarModel.coordinateSystem = calendar;
});
// Inject coordinate system
ecModel.eachComponent(function (mainType, componentModel) {
injectCoordSysByOption({
targetModel: componentModel,
coordSysType: 'calendar',
coordSysProvider: simpleCoordSysInjectionProvider
});
});
return calendarList;
};
Calendar.dimensions = ['time', 'value'];
return Calendar;
}();
function getCoordSys(finder) {
var calendarModel = finder.calendarModel;
var seriesModel = finder.seriesModel;
var coordSys = calendarModel ? calendarModel.coordinateSystem : seriesModel ? seriesModel.coordinateSystem : null;
return coordSys;
}
export default Calendar;
+166
View File
@@ -0,0 +1,166 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import ComponentModel from '../../model/Component.js';
import { getLayoutParams, sizeCalculable, mergeLayoutParam } from '../../util/layout.js';
import tokens from '../../visual/tokens.js';
var CalendarModel = /** @class */function (_super) {
__extends(CalendarModel, _super);
function CalendarModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = CalendarModel.type;
return _this;
}
/**
* @override
*/
CalendarModel.prototype.init = function (option, parentModel, ecModel) {
var inputPositionParams = getLayoutParams(option);
_super.prototype.init.apply(this, arguments);
mergeAndNormalizeLayoutParams(option, inputPositionParams);
};
/**
* @override
*/
CalendarModel.prototype.mergeOption = function (option) {
_super.prototype.mergeOption.apply(this, arguments);
mergeAndNormalizeLayoutParams(this.option, option);
};
CalendarModel.prototype.getCellSize = function () {
// Has been normalized
return this.option.cellSize;
};
CalendarModel.type = 'calendar';
CalendarModel.layoutMode = 'box';
CalendarModel.defaultOption = {
// zlevel: 0,
// TODO: theoretically, the z of the calendar should be lower
// than series, but we don't want the series to be displayed
// on top of the borders like month split line. To align with
// the effect of previous versions, we set the z to 2 for now
// until better solution is found.
z: 2,
left: 80,
top: 60,
cellSize: 20,
// horizontal vertical
orient: 'horizontal',
// month separate line style
splitLine: {
show: true,
lineStyle: {
color: tokens.color.axisLine,
width: 1,
type: 'solid'
}
},
// rect style temporarily unused emphasis
itemStyle: {
color: tokens.color.neutral00,
borderWidth: 1,
borderColor: tokens.color.neutral10
},
// week text style
dayLabel: {
show: true,
firstDay: 0,
// start end
position: 'start',
margin: tokens.size.s,
color: tokens.color.secondary
},
// month text style
monthLabel: {
show: true,
// start end
position: 'start',
margin: tokens.size.s,
// center or left
align: 'center',
formatter: null,
color: tokens.color.secondary
},
// year text style
yearLabel: {
show: true,
// top bottom left right
position: null,
margin: tokens.size.xl,
formatter: null,
color: tokens.color.quaternary,
fontFamily: 'sans-serif',
fontWeight: 'bolder',
fontSize: 20
}
};
return CalendarModel;
}(ComponentModel);
function mergeAndNormalizeLayoutParams(target, raw) {
// Normalize cellSize
var cellSize = target.cellSize;
var cellSizeArr;
if (!zrUtil.isArray(cellSize)) {
cellSizeArr = target.cellSize = [cellSize, cellSize];
} else {
cellSizeArr = cellSize;
}
if (cellSizeArr.length === 1) {
cellSizeArr[1] = cellSizeArr[0];
}
var ignoreSize = zrUtil.map([0, 1], function (hvIdx) {
// If user have set `width` or both `left` and `right`, cellSizeArr
// will be automatically set to 'auto', otherwise the default
// setting of cellSizeArr will make `width` setting not work.
if (sizeCalculable(raw, hvIdx)) {
cellSizeArr[hvIdx] = 'auto';
}
return cellSizeArr[hvIdx] != null && cellSizeArr[hvIdx] !== 'auto';
});
mergeLayoutParam(target, raw, {
type: 'box',
ignoreSize: ignoreSize
});
}
export default CalendarModel;
+72
View File
@@ -0,0 +1,72 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
export default function calendarPrepareCustom(coordSys) {
var rect = coordSys.getRect();
var rangeInfo = coordSys.getRangeInfo();
return {
coordSys: {
type: 'calendar',
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
cellWidth: coordSys.getCellWidth(),
cellHeight: coordSys.getCellHeight(),
rangeInfo: {
start: rangeInfo.start,
end: rangeInfo.end,
weeks: rangeInfo.weeks,
dayCount: rangeInfo.allDay
}
},
api: {
coord: function (data, clamp) {
return coordSys.dataToPoint(data, clamp);
},
layout: function (data, clamp) {
return coordSys.dataToLayout(data, clamp);
}
}
};
}
+94
View File
@@ -0,0 +1,94 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import Axis from '../Axis.js';
var Axis2D = /** @class */function (_super) {
__extends(Axis2D, _super);
function Axis2D(dim, scale, coordExtent, axisType, position) {
var _this = _super.call(this, dim, scale, coordExtent) || this;
/**
* Index of axis, can be used as key
* Injected outside.
*/
_this.index = 0;
_this.type = axisType || 'value';
_this.position = position || 'bottom';
return _this;
}
Axis2D.prototype.isHorizontal = function () {
var position = this.position;
return position === 'top' || position === 'bottom';
};
/**
* Each item cooresponds to this.getExtent(), which
* means globalExtent[0] may greater than globalExtent[1],
* unless `asc` is input.
*
* @param {boolean} [asc]
* @return {Array.<number>}
*/
Axis2D.prototype.getGlobalExtent = function (asc) {
var ret = this.getExtent();
ret[0] = this.toGlobalCoord(ret[0]);
ret[1] = this.toGlobalCoord(ret[1]);
asc && ret[0] > ret[1] && ret.reverse();
return ret;
};
Axis2D.prototype.pointToData = function (point, clamp) {
return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);
};
/**
* Set ordinalSortInfo
* @param info new OrdinalSortInfo
*/
Axis2D.prototype.setCategorySortInfo = function (info) {
if (this.type !== 'category') {
return false;
}
this.model.option.categorySortInfo = info;
this.scale.setSortInfo(info);
};
return Axis2D;
}(Axis);
export default Axis2D;
+62
View File
@@ -0,0 +1,62 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import ComponentModel from '../../model/Component.js';
import { AxisModelCommonMixin } from '../axisModelCommonMixin.js';
import { SINGLE_REFERRING } from '../../util/model.js';
var CartesianAxisModel = /** @class */function (_super) {
__extends(CartesianAxisModel, _super);
function CartesianAxisModel() {
return _super !== null && _super.apply(this, arguments) || this;
}
CartesianAxisModel.prototype.getCoordSysModel = function () {
return this.getReferringComponents('grid', SINGLE_REFERRING).models[0];
};
CartesianAxisModel.type = 'cartesian2dAxis';
return CartesianAxisModel;
}(ComponentModel);
export { CartesianAxisModel };
zrUtil.mixin(CartesianAxisModel, AxisModelCommonMixin);
export default CartesianAxisModel;
+74
View File
@@ -0,0 +1,74 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
var Cartesian = /** @class */function () {
function Cartesian(name) {
this.type = 'cartesian';
this._dimList = [];
this._axes = {};
this.name = name || '';
}
Cartesian.prototype.getAxis = function (dim) {
return this._axes[dim];
};
Cartesian.prototype.getAxes = function () {
return zrUtil.map(this._dimList, function (dim) {
return this._axes[dim];
}, this);
};
Cartesian.prototype.getAxesByScale = function (scaleType) {
scaleType = scaleType.toLowerCase();
return zrUtil.filter(this.getAxes(), function (axis) {
return axis.scale.type === scaleType;
});
};
Cartesian.prototype.addAxis = function (axis) {
var dim = axis.dim;
this._axes[dim] = axis;
this._dimList.push(dim);
};
return Cartesian;
}();
;
export default Cartesian;
+182
View File
@@ -0,0 +1,182 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import BoundingRect from 'zrender/lib/core/BoundingRect.js';
import Cartesian from './Cartesian.js';
import { COORD_SYS_TYPE_CARTESIAN_2D } from './GridModel.js';
import { invert } from 'zrender/lib/core/matrix.js';
import { applyTransform } from 'zrender/lib/core/vector.js';
import { getScaleExtentForMappingUnsafe } from '../../scale/scaleMapper.js';
import { hasBreaks } from '../../scale/break.js';
export var cartesian2DDimensions = ['x', 'y'];
function canCalculateAffineTransform(scale) {
// Only supported on linear space.
return (scale.type === 'interval' || scale.type === 'time') && !hasBreaks(scale);
}
var Cartesian2D = /** @class */function (_super) {
__extends(Cartesian2D, _super);
function Cartesian2D() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = COORD_SYS_TYPE_CARTESIAN_2D;
_this.dimensions = cartesian2DDimensions;
return _this;
}
/**
* Calculate an affine transform matrix if two axes are time or value.
* It's mainly for accelartion on the large time series data.
*/
Cartesian2D.prototype.calcAffineTransform = function () {
this._transform = this._invTransform = null;
var xAxisScale = this.getAxis('x').scale;
var yAxisScale = this.getAxis('y').scale;
if (!canCalculateAffineTransform(xAxisScale) || !canCalculateAffineTransform(yAxisScale)) {
return;
}
var xScaleExtent = getScaleExtentForMappingUnsafe(xAxisScale, null);
var yScaleExtent = getScaleExtentForMappingUnsafe(yAxisScale, null);
var start = this.dataToPoint([xScaleExtent[0], yScaleExtent[0]]);
var end = this.dataToPoint([xScaleExtent[1], yScaleExtent[1]]);
var xScaleSpan = xScaleExtent[1] - xScaleExtent[0];
var yScaleSpan = yScaleExtent[1] - yScaleExtent[0];
if (!xScaleSpan || !yScaleSpan) {
return;
}
// Accelerate data to point calculation on the special large time series data.
var scaleX = (end[0] - start[0]) / xScaleSpan;
var scaleY = (end[1] - start[1]) / yScaleSpan;
var translateX = start[0] - xScaleExtent[0] * scaleX;
var translateY = start[1] - yScaleExtent[0] * scaleY;
var m = this._transform = [scaleX, 0, 0, scaleY, translateX, translateY];
this._invTransform = invert([], m);
};
/**
* Base axis will be used on stacking and series such as 'bar', 'pictorialBar', etc.
*/
Cartesian2D.prototype.getBaseAxis = function () {
// FIXME:
// (1) We should allow series (e.g., bar) to specify a base axis when
// both axes are type "value", rather than force to xAxis or angleAxis.
// NOTE: At present BoxplotSeries has its own overide `getBaseAxis`.
// `CoordinateSystem['getBaseAxis']` probably should not exist, since it
// may introduce inconsistency with `Series['getBaseAxis']`.
// (2) "base axis" info is required in "createSeriesData" stage for "stack",
// (see `dataStackHelper.ts` for details). Currently it is hard coded there.
return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAxis('x');
};
Cartesian2D.prototype.containPoint = function (point) {
var axisX = this.getAxis('x');
var axisY = this.getAxis('y');
return axisX.contain(axisX.toLocalCoord(point[0])) && axisY.contain(axisY.toLocalCoord(point[1]));
};
Cartesian2D.prototype.containData = function (data) {
return this.getAxis('x').containData(data[0]) && this.getAxis('y').containData(data[1]);
};
Cartesian2D.prototype.containZone = function (data1, data2) {
var zoneDiag1 = this.dataToPoint(data1);
var zoneDiag2 = this.dataToPoint(data2);
var area = this.getArea();
var zone = new BoundingRect(zoneDiag1[0], zoneDiag1[1], zoneDiag2[0] - zoneDiag1[0], zoneDiag2[1] - zoneDiag1[1]);
return area.intersect(zone);
};
Cartesian2D.prototype.dataToPoint = function (data, clamp, out) {
out = out || [];
var xVal = data[0];
var yVal = data[1];
// [CAVEAT]: Do not add time consuming operation within and before fast path.
// Fast path.
if (this._transform
// It's supported that if data is like `[Inifity, 123]`, where only Y pixel calculated.
&& xVal != null && isFinite(xVal) && yVal != null && isFinite(yVal)) {
return applyTransform(out, data, this._transform);
}
var xAxis = this.getAxis('x');
var yAxis = this.getAxis('y');
out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(xVal, clamp));
out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(yVal, clamp));
return out;
};
Cartesian2D.prototype.clampData = function (data, out) {
var xScale = this.getAxis('x').scale;
var yScale = this.getAxis('y').scale;
var xAxisExtent = xScale.getExtent();
var yAxisExtent = yScale.getExtent();
var x = xScale.parse(data[0]);
var y = yScale.parse(data[1]);
out = out || [];
out[0] = Math.min(Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x), Math.max(xAxisExtent[0], xAxisExtent[1]));
out[1] = Math.min(Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y), Math.max(yAxisExtent[0], yAxisExtent[1]));
return out;
};
Cartesian2D.prototype.pointToData = function (point, clamp, out) {
out = out || [];
if (this._invTransform) {
return applyTransform(out, point, this._invTransform);
}
var xAxis = this.getAxis('x');
var yAxis = this.getAxis('y');
out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]), clamp);
out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]), clamp);
return out;
};
Cartesian2D.prototype.getOtherAxis = function (axis) {
return this.getAxis(axis.dim === 'x' ? 'y' : 'x');
};
/**
* Get rect area of cartesian.
* Area will have a contain function to determine if a point is in the coordinate system.
*/
Cartesian2D.prototype.getArea = function (tolerance) {
tolerance = tolerance || 0;
var xExtent = this.getAxis('x').getGlobalExtent();
var yExtent = this.getAxis('y').getGlobalExtent();
var x = Math.min(xExtent[0], xExtent[1]) - tolerance;
var y = Math.min(yExtent[0], yExtent[1]) - tolerance;
var width = Math.max(xExtent[0], xExtent[1]) - x + tolerance;
var height = Math.max(yExtent[0], yExtent[1]) - y + tolerance;
return new BoundingRect(x, y, width, height);
};
return Cartesian2D;
}(Cartesian);
;
export default Cartesian2D;
+801
View File
@@ -0,0 +1,801 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
/**
* Grid is a region which contains at most 4 cartesian systems
*
* TODO Default cartesian
*/
import { isObject, each, indexOf, retrieve3, keys, assert, eqNaN, find, retrieve2, hasOwn } from 'zrender/lib/core/util.js';
import { createBoxLayoutReference, getLayoutRect } from '../../util/layout.js';
import { createScaleByModel, getScaleValuePositionKind, isNameLocationCenter, shouldAxisShow, retrieveAxisBreaksOption, determineAxisType, isOnAxisZeroDiscouraged, SCALE_VALUE_POSITION_KIND_OUTSIDE, getTickValueOutermost, isAxisOnBand } from '../../coord/axisHelper.js';
import Cartesian2D, { cartesian2DDimensions } from './Cartesian2D.js';
import Axis2D from './Axis2D.js';
import { SINGLE_REFERRING } from '../../util/model.js';
// Depends on GridModel, AxisModel, which performs preprocess.
import { COORD_SYS_TYPE_CARTESIAN_2D, OUTER_BOUNDS_CLAMP_DEFAULT, OUTER_BOUNDS_DEFAULT } from './GridModel.js';
import { findAxisModels, createCartesianAxisViewCommonPartBuilder, updateCartesianAxisViewCommonPartBuilder } from './cartesianAxisHelper.js';
import { isIntervalOrLogScale, isOrdinalScale } from '../../scale/helper.js';
import { scaleCalcAlign } from '../axisAlignTicks.js';
import { expandOrShrinkRect, WH, XY } from '../../util/graphic.js';
import { AxisBuilderSharedContext, resolveAxisNameOverlapDefault, moveIfOverlapByLinearLabels, getLabelInner } from '../../component/axis/AxisBuilder.js';
import { error, log } from '../../util/log.js';
import { AxisTickLabelComputingKind } from '../axisTickLabelBuilder.js';
import { injectCoordSysByOption } from '../../core/CoordinateSystem.js';
import { mathMax, parsePositionSizeOption } from '../../util/number.js';
import { scaleCalcNice } from '../axisNiceTicks.js';
import { createDimNameMap } from '../../data/helper/SeriesDataSchema.js';
import { AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE, scaleRawExtentInfoEnableBoxCoordSysUsage, scaleRawExtentInfoCreate } from '../scaleRawExtentInfo.js';
import { hasBreaks } from '../../scale/break.js';
import { associateSeriesWithAxis } from '../axisStatistics.js';
// margin is [top, right, bottom, left]
var XY_TO_MARGIN_IDX = [[3, 1], [0, 2] // xyIdx 1 => 'y'
];
var Grid = /** @class */function () {
function Grid(gridModel, ecModel, api) {
// FIXME:TS where used (different from registered type 'cartesian2d')?
this.type = 'grid';
this._coordsMap = {};
this._coordsList = [];
this._axesMap = {};
this._axesList = [];
this.axisPointerEnabled = true;
this.dimensions = cartesian2DDimensions;
this._initCartesian(gridModel, ecModel, api);
this.model = gridModel;
}
Grid.prototype.getRect = function () {
return this._rect;
};
Grid.prototype.update = function (ecModel, api) {
var axesMap = this._axesMap;
each(this._axesList, function (axis) {
scaleRawExtentInfoCreate(axis, AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE);
var scale = axis.scale;
if (isOrdinalScale(scale)) {
scale.setSortInfo(axis.model.get('categorySortInfo'));
}
});
function updateAxisTicks(axes) {
// Axis is added in order of axisIndex.
var axesIndices = keys(axes);
var axisNeedsAlign = [];
for (var i = axesIndices.length - 1; i >= 0; i--) {
// Reverse order
var axis = axes[+axesIndices[i]];
if (axis.__alignTo) {
axisNeedsAlign.push(axis);
} else {
scaleCalcNice(axis);
}
}
;
each(axisNeedsAlign, function (axis) {
if (incapableOfAlignNeedFallback(axis, axis.__alignTo)) {
scaleCalcNice(axis);
} else {
scaleCalcAlign(axis, axis.__alignTo.scale);
}
});
}
updateAxisTicks(axesMap.x);
updateAxisTicks(axesMap.y);
// Key: axisDim_axisIndex, value: boolean, whether onZero target.
var onZeroRecords = {};
each(axesMap.x, function (xAxis) {
fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);
});
each(axesMap.y, function (yAxis) {
fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);
});
// Resize again if containLabel is enabled
// FIXME It may cause getting wrong grid size in data processing stage
this.resize(this.model, api);
};
/**
* Resize the grid.
*
* [NOTE]
* If both "grid.containLabel/grid.contain" and pixel-required-data-processing (such as, "dataSampling")
* exist, circular dependency occurs in logic.
* The final compromised sequence is:
* 1. Calculate "axis.extent" (pixel extent) and AffineTransform based on only "grid layout options".
* Not accurate if "grid.containLabel/grid.contain" is required, but it is a compromise to avoid
* circular dependency.
* 2. Perform "series data processing" (where "dataSampling" requires "axis.extent").
* 3. Calculate "scale.extent" (data extent) based on "processed series data".
* 4. Modify "axis.extent" for "grid.containLabel/grid.contain":
* 4.1. Calculate "axis labels" based on "scale.extent".
* 4.2. Modify "axis.extent" by the bounding rects of "axis labels and names".
*/
Grid.prototype.resize = function (gridModel, api, beforeDataProcessing) {
var layoutRef = createBoxLayoutReference(gridModel, api);
var gridRect = this._rect = getLayoutRect(gridModel.getBoxLayoutParams(), layoutRef.refContainer);
// PENDING: whether to support that if the input `coord` is out of the base coord sys,
// do not render anything. At present, the behavior is undefined.
var axesMap = this._axesMap;
var coordsList = this._coordsList;
var optionContainLabel = gridModel.get('containLabel'); // No `.get(, true)` for backward compat.
// NOTE: The axis pixel extent is also required by some estimation, e.g., in coord sys update stage,
// bars on 'time'/'value' axis need it to calculate the supplementary scale extent to avoid edge bars
// overflowing the axis (see `barGrid.ts`). Therefore, axis pixel extent need to be set early, even
// may not be accurate.
updateAllAxisExtentTransByGridRect(axesMap, gridRect);
if (!beforeDataProcessing) {
var axisBuilderSharedCtx = createAxisBiulders(gridRect, coordsList, axesMap, optionContainLabel, api);
var noPxChange = void 0;
if (optionContainLabel) {
if (legacyLayOutGridByContainLabel) {
// console.time('legacyLayOutGridByContainLabel');
legacyLayOutGridByContainLabel(this._axesList, gridRect);
updateAllAxisExtentTransByGridRect(axesMap, gridRect);
// console.timeEnd('legacyLayOutGridByContainLabel');
} else {
if (process.env.NODE_ENV !== 'production') {
log('Specified `grid.containLabel` but no `use(LegacyGridContainLabel)`;' + 'use `grid.outerBounds` instead.', true);
}
noPxChange = layOutGridByOuterBounds(gridRect.clone(), 'axisLabel', null, gridRect, axesMap, axisBuilderSharedCtx, layoutRef);
}
} else {
var _a = prepareOuterBounds(gridModel, gridRect, layoutRef),
outerBoundsRect = _a.outerBoundsRect,
parsedOuterBoundsContain = _a.parsedOuterBoundsContain,
outerBoundsClamp = _a.outerBoundsClamp;
if (outerBoundsRect) {
// console.time('layOutGridByOuterBounds');
noPxChange = layOutGridByOuterBounds(outerBoundsRect, parsedOuterBoundsContain, outerBoundsClamp, gridRect, axesMap, axisBuilderSharedCtx, layoutRef);
// console.timeEnd('layOutGridByOuterBounds');
}
}
// console.time('buildAxesView_determine');
createOrUpdateAxesView(gridRect, axesMap, AxisTickLabelComputingKind.determine, null, noPxChange, layoutRef);
// console.timeEnd('buildAxesView_determine');
each(this._coordsList, function (coord) {
// Calculate affine matrix to accelerate the data to point transform.
// If all the axes scales are time or value.
coord.calcAffineTransform();
});
} // End of beforeDataProcessing
};
Grid.prototype.getAxis = function (dim, axisIndex) {
var axesMapOnDim = this._axesMap[dim];
if (axesMapOnDim != null) {
return axesMapOnDim[axisIndex || 0];
}
};
Grid.prototype.getAxes = function () {
return this._axesList.slice();
};
Grid.prototype.getCartesian = function (xAxisIndex, yAxisIndex) {
if (xAxisIndex != null && yAxisIndex != null) {
var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
return this._coordsMap[key];
}
if (isObject(xAxisIndex)) {
yAxisIndex = xAxisIndex.yAxisIndex;
xAxisIndex = xAxisIndex.xAxisIndex;
}
for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {
if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex) {
return coordList[i];
}
}
};
Grid.prototype.getCartesians = function () {
return this._coordsList.slice();
};
/**
* @implements
*/
Grid.prototype.convertToPixel = function (ecModel, finder, value) {
var target = this._findConvertTarget(finder);
return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null;
};
/**
* @implements
*/
Grid.prototype.convertFromPixel = function (ecModel, finder, value) {
var target = this._findConvertTarget(finder);
return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null;
};
Grid.prototype._findConvertTarget = function (finder) {
var seriesModel = finder.seriesModel;
var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0];
var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0];
var gridModel = finder.gridModel;
var coordsList = this._coordsList;
var cartesian;
var axis;
if (seriesModel) {
cartesian = seriesModel.coordinateSystem;
indexOf(coordsList, cartesian) < 0 && (cartesian = null);
} else if (xAxisModel && yAxisModel) {
cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
} else if (xAxisModel) {
axis = this.getAxis('x', xAxisModel.componentIndex);
} else if (yAxisModel) {
axis = this.getAxis('y', yAxisModel.componentIndex);
}
// Lowest priority.
else if (gridModel) {
var grid = gridModel.coordinateSystem;
if (grid === this) {
cartesian = this._coordsList[0];
}
}
return {
cartesian: cartesian,
axis: axis
};
};
/**
* @implements
*/
Grid.prototype.containPoint = function (point) {
var coord = this._coordsList[0];
if (coord) {
return coord.containPoint(point);
}
};
/**
* Initialize cartesian coordinate systems
*/
Grid.prototype._initCartesian = function (gridModel, ecModel, api) {
var _this = this;
var grid = this;
var axisPositionUsed = {
left: false,
right: false,
top: false,
bottom: false
};
var axesMap = {
x: {},
y: {}
};
var axesCount = {
x: 0,
y: 0
};
// Create axis
ecModel.eachComponent('xAxis', createAxisCreator('x'), this);
ecModel.eachComponent('yAxis', createAxisCreator('y'), this);
if (!axesCount.x || !axesCount.y) {
// Roll back when there no either x or y axis
this._axesMap = {};
this._axesList = [];
return;
}
this._axesMap = axesMap;
// Create cartesian2d
each(axesMap.x, function (xAxis, xAxisIndex) {
each(axesMap.y, function (yAxis, yAxisIndex) {
var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
var cartesian = new Cartesian2D(key);
cartesian.master = _this;
cartesian.model = gridModel;
_this._coordsMap[key] = cartesian;
_this._coordsList.push(cartesian);
cartesian.addAxis(xAxis);
cartesian.addAxis(yAxis);
});
});
prepareAlignToInCoordSysCreate(axesMap.x);
prepareAlignToInCoordSysCreate(axesMap.y);
function createAxisCreator(dimName) {
return function (axisModel, idx) {
if (!isAxisUsedInTheGrid(axisModel, gridModel)) {
return;
}
var axisPosition = axisModel.get('position');
if (dimName === 'x') {
// Fix position
if (axisPosition !== 'top' && axisPosition !== 'bottom') {
// Default bottom of X
axisPosition = axisPositionUsed.bottom ? 'top' : 'bottom';
}
} else {
// Fix position
if (axisPosition !== 'left' && axisPosition !== 'right') {
// Default left of Y
axisPosition = axisPositionUsed.left ? 'right' : 'left';
}
}
axisPositionUsed[axisPosition] = true;
var axisType = determineAxisType(axisModel);
var axis = new Axis2D(dimName, createScaleByModel(axisModel, axisType, true), [0, 0], axisType, axisPosition);
axis.onBand = isAxisOnBand(axis.scale, axisModel);
axis.inverse = axisModel.get('inverse');
// Inject axis into axisModel
axisModel.axis = axis;
// Inject axisModel into axis
axis.model = axisModel;
// Inject grid info axis
axis.grid = grid;
// Index of axis, can be used as key
axis.index = idx;
grid._axesList.push(axis);
axesMap[dimName][idx] = axis;
axesCount[dimName]++;
};
}
};
/**
* @param dim 'x' or 'y' or 'auto' or null/undefined
*/
Grid.prototype.getTooltipAxes = function (dim) {
var baseAxes = [];
var otherAxes = [];
each(this.getCartesians(), function (cartesian) {
var baseAxis = dim != null && dim !== 'auto' ? cartesian.getAxis(dim) : cartesian.getBaseAxis();
var otherAxis = cartesian.getOtherAxis(baseAxis);
indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);
indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);
});
return {
baseAxes: baseAxes,
otherAxes: otherAxes
};
};
Grid.create = function (ecModel, api) {
var grids = [];
ecModel.eachComponent('grid', function (gridModel, idx) {
var grid = new Grid(gridModel, ecModel, api);
grid.name = 'grid_' + idx;
// dataSampling requires axis extent, so resize
// should be performed in create stage.
grid.resize(gridModel, api, true);
gridModel.coordinateSystem = grid;
grids.push(grid);
each(grid._axesList, function (axis) {
scaleRawExtentInfoEnableBoxCoordSysUsage(axis, Grid.dimIdxMap);
});
});
// Inject the coordinateSystems into seriesModel
ecModel.eachSeries(function (seriesModel) {
var xAxis;
var yAxis;
injectCoordSysByOption({
targetModel: seriesModel,
coordSysType: COORD_SYS_TYPE_CARTESIAN_2D,
coordSysProvider: coordSysProvider
});
function coordSysProvider() {
var axesModelMap = findAxisModels(seriesModel);
var xAxisModel = axesModelMap.xAxisModel;
var yAxisModel = axesModelMap.yAxisModel;
xAxis = xAxisModel.axis;
yAxis = yAxisModel.axis;
var gridModel = xAxisModel.getCoordSysModel();
if (process.env.NODE_ENV !== 'production') {
if (!gridModel) {
throw new Error('Grid "' + retrieve3(xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0) + '" not found');
}
if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {
throw new Error('xAxis and yAxis must use the same grid');
}
}
var grid = gridModel.coordinateSystem;
return grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
}
if (xAxis && yAxis) {
associateSeriesWithAxis(xAxis, seriesModel, COORD_SYS_TYPE_CARTESIAN_2D);
associateSeriesWithAxis(yAxis, seriesModel, COORD_SYS_TYPE_CARTESIAN_2D);
}
}, this);
return grids;
};
// For deciding which dimensions to use when creating list data
Grid.dimensions = cartesian2DDimensions;
Grid.dimIdxMap = createDimNameMap(cartesian2DDimensions);
return Grid;
}();
/**
* Check if the axis is used in the specified grid.
*/
function isAxisUsedInTheGrid(axisModel, gridModel) {
return axisModel.getCoordSysModel() === gridModel;
}
function fixAxisOnZero(axesMap, otherAxisDim, axis,
// Key: see `getOnZeroRecordKey`
onZeroRecords) {
axis.getAxesOnZeroOf = function () {
// TODO: onZero of multiple axes.
return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];
};
// onZero can not be enabled in these two situations:
// 1. When any other axis is a category axis.
// 2. When no axis is cross 0 point.
var otherAxes = axesMap[otherAxisDim];
var otherAxisOnZeroOf;
var axisModel = axis.model;
var onZero = axisModel.get(['axisLine', 'onZero']);
var onZeroAxisIndex = axisModel.get(['axisLine', 'onZeroAxisIndex']);
// For historical reason, ec option `axisLine.onZero: undefined` leads to "not on zero"
// while leaving `axisLine.onZero` unspecified causes "on zero". This inconsistency goes
// against common sense, but is preserved for backward compatibility.
if (!onZero) {
return;
}
// If target axis is specified.
if (onZeroAxisIndex != null) {
if (canOnZeroToAxis(onZero, otherAxes[onZeroAxisIndex])) {
otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];
}
} else {
// Find the first available other axis.
for (var idx in otherAxes) {
if (hasOwn(otherAxes, idx) && canOnZeroToAxis(onZero, otherAxes[idx])
// Consider that two Y axes on one value axis,
// if both onZero, the two Y axes overlap.
&& !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]) {
otherAxisOnZeroOf = otherAxes[idx];
break;
}
}
}
if (otherAxisOnZeroOf) {
onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;
}
function getOnZeroRecordKey(axis) {
return axis.dim + '_' + axis.index;
}
}
/**
* CAVEAT: Must not be called before `CoordinateSystem#update` due to `__dontOnMyZero`.
*/
function canOnZeroToAxis(onZeroOption, axis) {
if (!axis) {
return false;
}
var scale = axis.scale;
var kindEffective = getScaleValuePositionKind(scale, 0, false);
var can = axis
// PENDING: Historical behavior: `onZero` on 'category' and 'time' axis are always disabled
// even if ec option gives `onZero: true`.
&& axis.type !== 'category' && axis.type !== 'time'
// NOTE: Although the portion out of "effective" portion may also cross zero
// (see `SCALE_EXTENT_KIND_MAPPING`), that is commonly meaningless, so we use
// `SCALE_EXTENT_KIND_EFFECTIVE`
&& kindEffective !== SCALE_VALUE_POSITION_KIND_OUTSIDE;
if (can && onZeroOption === 'auto'
// Historically, "value" axis and "log" axis has been using `onZero: true` as the default.
// It suitable for mathematic cases, even when dataZoom exists (e.g., `clip.html`), or cases
// need to distinguish positive and negative data. However, it probably causes odd effect if
// a "value axis" is laid on zero of a "base axis" in bar/candlestick, where the axis line
// would likely cross shapes when `SCALE_EXTENT_KIND_MAPPING` is applied.
// Therefore, we preserve backward compatibility of the default `onZero: true`, but exclude
// cases that `containShape` is applied.
&& isOnAxisZeroDiscouraged(axis)
// || (
// // Avoid axis line cross series shape (typically, bar series on "value"/"time" axis) unexpectedly.
// kindEffective === SCALE_VALUE_POSITION_KIND_EDGE
// && getScaleValuePositionKind(scale, 0, true) === SCALE_VALUE_POSITION_KIND_INSIDE
// )
) {
can = false;
}
// falsy value of `onZeroOption` has been handled in the previous logic.
return can;
}
/**
* [CAVEAT] This method is called before data processing stage.
* Do not rely on any info that is determined afterward.
*/
function prepareAlignToInCoordSysCreate(axes) {
// Axis is added in order of axisIndex.
var axesIndices = keys(axes);
var alignTo;
var axisNeedsAlign = [];
for (var i = axesIndices.length - 1; i >= 0; i--) {
// Reverse order
var axis = axes[+axesIndices[i]];
if (isIntervalOrLogScale(axis.scale)
// NOTE: `scale.hasBreaks()` is not available at this moment. Check it later.
&& retrieveAxisBreaksOption(axis.model, axis.type, true) == null
// NOTE: `scale.getTicks()` is not available at this moment. Check it later.
) {
// Request `alignTicks`.
if (axis.model.get('alignTicks') && axis.model.get('interval') == null) {
axisNeedsAlign.push(axis);
} else {
// `alignTo` the last one that does not request `alignTicks`
// (This rule is retained for backward compat).
alignTo = axis;
}
}
}
;
// If all axes has set alignTicks, pick the first one as alignTo.
// PENDING. Should we find the axis that both set interval, min, max and align to this one?
// PENDING. Should we allow specifying alignTo via ec option?
if (!alignTo) {
alignTo = axisNeedsAlign.pop();
}
if (alignTo) {
each(axisNeedsAlign, function (axis) {
axis.__alignTo = alignTo;
});
}
}
/**
* This is just a defence code. They are unlikely to be actually `true`,
* since these cases have been addressed in `prepareAlignToInCoordSysCreate`.
*
* Can not be called BEFORE "nice" performed.
*/
function incapableOfAlignNeedFallback(targetAxis, alignTo) {
return hasBreaks(targetAxis.scale) || hasBreaks(alignTo.scale)
// Normally ticks length are more than 2 even when axis is blank.
// But still guard for corner cases and possible changes.
|| alignTo.scale.getTicks().length < 2;
}
function updateAxisTransform(axis, coordBase) {
var axisExtent = axis.getExtent();
var axisExtentSum = axisExtent[0] + axisExtent[1];
// Fast transform
axis.toGlobalCoord = axis.dim === 'x' ? function (coord) {
return coord + coordBase;
} : function (coord) {
return axisExtentSum - coord + coordBase;
};
axis.toLocalCoord = axis.dim === 'x' ? function (coord) {
return coord - coordBase;
} : function (coord) {
return axisExtentSum - coord + coordBase;
};
}
function updateAllAxisExtentTransByGridRect(axesMap, gridRect) {
each(axesMap.x, function (axis) {
return updateAxisExtentTransByGridRect(axis, gridRect.x, gridRect.width);
});
each(axesMap.y, function (axis) {
return updateAxisExtentTransByGridRect(axis, gridRect.y, gridRect.height);
});
}
function updateAxisExtentTransByGridRect(axis, gridXY, gridWH) {
var extent = [0, gridWH];
var idx = axis.inverse ? 1 : 0;
axis.setExtent(extent[idx], extent[1 - idx]);
updateAxisTransform(axis, gridXY);
}
var legacyLayOutGridByContainLabel;
export function registerLegacyGridContainLabelImpl(impl) {
legacyLayOutGridByContainLabel = impl;
}
// Return noPxChange.
function layOutGridByOuterBounds(outerBoundsRect, outerBoundsContain, outerBoundsClamp, gridRect, axesMap, axisBuilderSharedCtx, layoutRef) {
if (process.env.NODE_ENV !== 'production') {
assert(outerBoundsContain === 'all' || outerBoundsContain === 'axisLabel');
}
// Assume `updateAllAxisExtentTransByGridRect` has been performed once before this call.
// [NOTE]:
// - The bounding rect of the axis elements might be sensitve to variations in `axis.extent` due to strategies
// like hideOverlap/moveOverlap. @see the comment in `LabelLayoutBase['suggestIgnore']`.
// - The final `gridRect` might be slightly smaller than the ideally expected result if labels are giant and
// get hidden due to overlapping. More iterations could improve precision, but not performant. We consider
// the current result acceptable, since no alignment among charts can be guaranteed when using this feature.
createOrUpdateAxesView(gridRect, axesMap, AxisTickLabelComputingKind.estimate, outerBoundsContain, false, layoutRef);
var margin = [0, 0, 0, 0];
fillLabelNameOverflowOnOneDimension(0);
fillLabelNameOverflowOnOneDimension(1);
// If axis is blank, no label can be used to detect overflow.
// gridRect itself should not overflow.
fillMarginOnOneDimension(gridRect, 0, NaN);
fillMarginOnOneDimension(gridRect, 1, NaN);
var noPxChange = find(margin, function (item) {
return item > 0;
}) == null;
expandOrShrinkRect(gridRect, margin, true, true, outerBoundsClamp);
updateAllAxisExtentTransByGridRect(axesMap, gridRect);
return noPxChange;
function fillLabelNameOverflowOnOneDimension(xyIdx) {
each(axesMap[XY[xyIdx]], function (axis) {
if (!shouldAxisShow(axis.model)) {
return;
}
// FIXME: zr Group.union may wrongly union (0, 0, 0, 0) and not performant.
// unionRect.union(axis.axisBuilder.group.getBoundingRect());
// If ussing Group.getBoundingRect to calculate shrink space, it is not strictly accurate when
// the outermost label is ignored and the secondary label is very long and contribute to the
// union extension:
// -|---|---|---|
// 1,000,000,000
// Therefore we calculate them one by one.
// Also considered axis may be blank or no labels.
var sharedRecord = axisBuilderSharedCtx.ensureRecord(axis.model);
var labelInfoList = sharedRecord.labelInfoList;
if (labelInfoList) {
for (var idx = 0; idx < labelInfoList.length; idx++) {
var labelInfo = labelInfoList[idx];
var proportion = axis.scale.normalize(getTickValueOutermost(axis.scale, getLabelInner(labelInfo.label).labelInfo.tick));
proportion = xyIdx === 1 ? 1 - proportion : proportion;
// xAxis use proportion on x, yAxis use proprotion on y, otherwise not.
fillMarginOnOneDimension(labelInfo.rect, xyIdx, proportion);
fillMarginOnOneDimension(labelInfo.rect, 1 - xyIdx, NaN);
}
}
var nameLayout = sharedRecord.nameLayout;
if (nameLayout) {
var proportion = isNameLocationCenter(sharedRecord.nameLocation) ? 0.5 : NaN;
fillMarginOnOneDimension(nameLayout.rect, xyIdx, proportion);
fillMarginOnOneDimension(nameLayout.rect, 1 - xyIdx, NaN);
}
});
}
function fillMarginOnOneDimension(itemRect, xyIdx, proportion // NaN mean no use proportion
) {
var overflow1 = outerBoundsRect[XY[xyIdx]] - itemRect[XY[xyIdx]];
var overflow2 = itemRect[WH[xyIdx]] + itemRect[XY[xyIdx]] - (outerBoundsRect[WH[xyIdx]] + outerBoundsRect[XY[xyIdx]]);
overflow1 = applyProportion(overflow1, 1 - proportion);
overflow2 = applyProportion(overflow2, proportion);
var minIdx = XY_TO_MARGIN_IDX[xyIdx][0];
var maxIdx = XY_TO_MARGIN_IDX[xyIdx][1];
margin[minIdx] = mathMax(margin[minIdx], overflow1);
margin[maxIdx] = mathMax(margin[maxIdx], overflow2);
}
function applyProportion(overflow, proportion) {
// proportion is not likely to near zero. If so, give up shrink
if (overflow > 0 && !eqNaN(proportion) && proportion > 1e-4) {
overflow /= proportion;
}
return overflow;
}
}
function createAxisBiulders(gridRect, cartesians, axesMap, optionContainLabel, api) {
var axisBuilderSharedCtx = new AxisBuilderSharedContext(resolveAxisNameOverlapForGrid);
each(axesMap, function (axisList) {
return each(axisList, function (axis) {
if (shouldAxisShow(axis.model)) {
// See `AxisBaseOptionCommon['nameMoveOverlap']`.
var defaultNameMoveOverlap = !optionContainLabel;
axis.axisBuilder = createCartesianAxisViewCommonPartBuilder(gridRect, cartesians, axis.model, api, axisBuilderSharedCtx, defaultNameMoveOverlap);
}
});
});
return axisBuilderSharedCtx;
}
/**
* Promote the axis-elements-building from "view render" stage to "coordinate system resize" stage.
* This is aimed to resovle overlap across multiple axes, since currently it's hard to reconcile
* multiple axes in "view render" stage.
*
* [CAUTION] But this promotion assumes that the subsequent "visual mapping" stage does not affect
* this axis-elements-building; otherwise we have to refactor it again.
*/
function createOrUpdateAxesView(gridRect, axesMap, kind, outerBoundsContain, noPxChange, layoutRef) {
var isDetermine = kind === AxisTickLabelComputingKind.determine;
each(axesMap, function (axisList) {
return each(axisList, function (axis) {
if (shouldAxisShow(axis.model)) {
updateCartesianAxisViewCommonPartBuilder(axis.axisBuilder, gridRect, axis.model);
axis.axisBuilder.build(isDetermine ? {
axisTickLabelDetermine: true
} : {
axisTickLabelEstimate: true
}, {
noPxChange: noPxChange
});
}
});
});
var nameMarginLevelMap = {
x: 0,
y: 0
};
calcNameMarginLevel(0);
calcNameMarginLevel(1);
function calcNameMarginLevel(xyIdx) {
nameMarginLevelMap[XY[1 - xyIdx]] = gridRect[WH[xyIdx]] <= layoutRef.refContainer[WH[xyIdx]] * 0.5 ? 0 : 1 - xyIdx === 1 ? 2 : 1;
}
each(axesMap, function (axisList, xy) {
return each(axisList, function (axis) {
if (shouldAxisShow(axis.model)) {
if (outerBoundsContain === 'all' || isDetermine) {
// To resolve overlap, `axisName` layout depends on `axisTickLabel` layout result
// (all of the axes of the same `grid`; consider multiple x or y axes).
axis.axisBuilder.build({
axisName: true
}, {
nameMarginLevel: nameMarginLevelMap[xy]
});
}
if (isDetermine) {
axis.axisBuilder.build({
axisLine: true
});
}
}
});
});
}
function prepareOuterBounds(gridModel, rawGridRect, layoutRef) {
var outerBoundsRect;
var optionOuterBoundsMode = gridModel.get('outerBoundsMode', true);
if (optionOuterBoundsMode === 'same') {
outerBoundsRect = rawGridRect.clone();
} else if (optionOuterBoundsMode == null || optionOuterBoundsMode === 'auto') {
outerBoundsRect = getLayoutRect(gridModel.get('outerBounds', true) || OUTER_BOUNDS_DEFAULT, layoutRef.refContainer);
} else if (optionOuterBoundsMode !== 'none') {
if (process.env.NODE_ENV !== 'production') {
error("Invalid grid[" + gridModel.componentIndex + "].outerBoundsMode.");
}
}
var optionOuterBoundsContain = gridModel.get('outerBoundsContain', true);
var parsedOuterBoundsContain;
if (optionOuterBoundsContain == null || optionOuterBoundsContain === 'auto') {
parsedOuterBoundsContain = 'all';
} else if (indexOf(['all', 'axisLabel'], optionOuterBoundsContain) < 0) {
if (process.env.NODE_ENV !== 'production') {
error("Invalid grid[" + gridModel.componentIndex + "].outerBoundsContain.");
}
parsedOuterBoundsContain = 'all';
} else {
parsedOuterBoundsContain = optionOuterBoundsContain;
}
var outerBoundsClamp = [parsePositionSizeOption(retrieve2(gridModel.get('outerBoundsClampWidth', true), OUTER_BOUNDS_CLAMP_DEFAULT[0]), rawGridRect.width), parsePositionSizeOption(retrieve2(gridModel.get('outerBoundsClampHeight', true), OUTER_BOUNDS_CLAMP_DEFAULT[1]), rawGridRect.height)];
return {
outerBoundsRect: outerBoundsRect,
parsedOuterBoundsContain: parsedOuterBoundsContain,
outerBoundsClamp: outerBoundsClamp
};
}
var resolveAxisNameOverlapForGrid = function (cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord) {
var perpendicularDim = axisModel.axis.dim === 'x' ? 'y' : 'x';
resolveAxisNameOverlapDefault(cfg, ctx, axisModel, nameLayoutInfo, nameMoveDirVec, thisRecord);
// If nameLocation 'center', and there are multiple axes parallel to this axis, do not adjust by
// other axes, because the axis name should be close to its axis line as much as possible even
// if overlapping; otherwise it might cause misleading.
// If nameLocation 'center', do not adjust by perpendicular axes, since they are not likely to overlap.
// If nameLocation 'start'/'end', move name within the same direction to escape overlap with the
// perpendicular axes.
if (!isNameLocationCenter(cfg.nameLocation)) {
each(ctx.recordMap[perpendicularDim], function (perpenRecord) {
// perpendicular axis may be no name.
if (perpenRecord && perpenRecord.labelInfoList && perpenRecord.dirVec) {
moveIfOverlapByLinearLabels(perpenRecord.labelInfoList, perpenRecord.dirVec, nameLayoutInfo, nameMoveDirVec);
}
});
}
};
export default Grid;
+102
View File
@@ -0,0 +1,102 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import ComponentModel from '../../model/Component.js';
import { getLayoutParams, mergeLayoutParam } from '../../util/layout.js';
import tokens from '../../visual/tokens.js';
// For backward compatibility, do not use a margin. Although the labels might touch the edge of
// the canvas, the chart canvas probably does not have an border or a different background color within a page.
export var OUTER_BOUNDS_DEFAULT = {
left: 0,
right: 0,
top: 0,
bottom: 0
};
export var OUTER_BOUNDS_CLAMP_DEFAULT = ['25%', '25%'];
export var COORD_SYS_TYPE_CARTESIAN_2D = 'cartesian2d';
var GridModel = /** @class */function (_super) {
__extends(GridModel, _super);
function GridModel() {
return _super !== null && _super.apply(this, arguments) || this;
}
GridModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
var outerBoundsCp = getLayoutParams(option.outerBounds);
_super.prototype.mergeDefaultAndTheme.apply(this, arguments);
if (outerBoundsCp && option.outerBounds) {
mergeLayoutParam(option.outerBounds, outerBoundsCp);
}
};
GridModel.prototype.mergeOption = function (newOption, ecModel) {
_super.prototype.mergeOption.apply(this, arguments);
if (this.option.outerBounds && newOption.outerBounds) {
mergeLayoutParam(this.option.outerBounds, newOption.outerBounds);
}
};
GridModel.type = 'grid';
GridModel.dependencies = ['xAxis', 'yAxis'];
GridModel.layoutMode = 'box';
GridModel.defaultOption = {
show: false,
// zlevel: 0,
z: 0,
left: '15%',
top: 65,
right: '10%',
bottom: 80,
// If grid size contain label
containLabel: false,
outerBoundsMode: 'auto',
outerBounds: OUTER_BOUNDS_DEFAULT,
outerBoundsContain: 'all',
outerBoundsClampWidth: OUTER_BOUNDS_CLAMP_DEFAULT[0],
outerBoundsClampHeight: OUTER_BOUNDS_CLAMP_DEFAULT[1],
// width: {totalWidth} - left - right,
// height: {totalHeight} - top - bottom,
backgroundColor: tokens.color.transparent,
borderWidth: 1,
borderColor: tokens.color.neutral30
};
return GridModel;
}(ComponentModel);
export default GridModel;
+169
View File
@@ -0,0 +1,169 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import { SINGLE_REFERRING } from '../../util/model.js';
import AxisBuilder from '../../component/axis/AxisBuilder.js';
import { isIntervalOrLogScale } from '../../scale/helper.js';
/**
* [__CAUTION__]
* MUST guarantee: if only the input `rect` and `axis.extent` changed,
* only `layout.position` changes.
* This character is replied on `grid.contain` calculation in `AxisBuilder`.
* @see updateCartesianAxisViewCommonPartBuilder
*
* Can only be called after coordinate system creation stage.
* (Can be called before coordinate system update stage).
*/
export function layout(rect, axisModel, opt) {
opt = opt || {};
var axis = axisModel.axis;
var layout = {};
var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];
var rawAxisPosition = axis.position;
var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;
var axisDim = axis.dim;
var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];
var idx = {
left: 0,
right: 1,
top: 0,
bottom: 1,
onZero: 2
};
var axisOffset = axisModel.get('offset') || 0;
var posBound = axisDim === 'x' ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset] : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];
if (otherAxisOnZeroOf) {
var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));
posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);
}
// Axis position
layout.position = [axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0], axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]];
// Axis rotation
layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1);
// Tick and label direction, x y is axisDim
var dirMap = {
top: -1,
bottom: 1,
left: -1,
right: 1
};
layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];
layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;
if (axisModel.get(['axisTick', 'inside'])) {
layout.tickDirection = -layout.tickDirection;
}
if (zrUtil.retrieve(opt.labelInside, axisModel.get(['axisLabel', 'inside']))) {
layout.labelDirection = -layout.labelDirection;
}
// Special label rotation
var labelRotate = axisModel.get(['axisLabel', 'rotate']);
layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;
// Over splitLine and splitArea
layout.z2 = 1;
return layout;
}
export function isCartesian2DDeclaredSeries(seriesModel) {
return seriesModel.get('coordinateSystem') === 'cartesian2d';
}
/**
* Note: If pie (or other similar series) use cartesian2d, here
* option `seriesModel.get('coordinateSystem') === 'cartesian2d'`
* and `seriesModel.coordinateSystem !== cartesian2dCoordSysInstance`
* and `seriesModel.boxCoordinateSystem === cartesian2dCoordSysInstance`,
* the logic below is probably wrong, therefore skip it temporarily.
*/
export function isCartesian2DInjectedAsDataCoordSys(seriesModel) {
return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';
}
export function findAxisModels(seriesModel) {
var axisModelMap = {
xAxisModel: null,
yAxisModel: null
};
zrUtil.each(axisModelMap, function (v, key) {
var axisType = key.replace(/Model$/, '');
var axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0];
if (process.env.NODE_ENV !== 'production') {
if (!axisModel) {
throw new Error(axisType + ' "' + zrUtil.retrieve3(seriesModel.get(axisType + 'Index'), seriesModel.get(axisType + 'Id'), 0) + '" not found');
}
}
axisModelMap[key] = axisModel;
});
return axisModelMap;
}
export function createCartesianAxisViewCommonPartBuilder(gridRect, cartesians, axisModel, api, ctx, defaultNameMoveOverlap) {
var layoutResult = layout(gridRect, axisModel);
var axisLineAutoShow = false;
var axisTickAutoShow = false;
// Not show axisTick or axisLine if other axis is category / time
for (var i = 0; i < cartesians.length; i++) {
if (isIntervalOrLogScale(cartesians[i].getOtherAxis(axisModel.axis).scale)) {
// Still show axis tick or axisLine if other axis is value / log
axisLineAutoShow = axisTickAutoShow = true;
if (axisModel.axis.type === 'category' && axisModel.axis.onBand) {
axisTickAutoShow = false;
}
}
}
layoutResult.axisLineAutoShow = axisLineAutoShow;
layoutResult.axisTickAutoShow = axisTickAutoShow;
layoutResult.defaultNameMoveOverlap = defaultNameMoveOverlap;
return new AxisBuilder(axisModel, api, layoutResult, ctx);
}
export function updateCartesianAxisViewCommonPartBuilder(axisBuilder, gridRect, axisModel) {
var newRaw = layout(gridRect, axisModel);
if (process.env.NODE_ENV !== 'production') {
var oldRaw_1 = axisBuilder.__getRawCfg();
zrUtil.each(zrUtil.keys(newRaw), function (prop) {
if (prop !== 'position' && prop !== 'labelOffset') {
zrUtil.assert(newRaw[prop] === oldRaw_1[prop]);
}
});
}
axisBuilder.updateCfg(newRaw);
}
export function getCartesianAxisHashKey(axis) {
return axis.dim + '_' + axis.index;
}
+291
View File
@@ -0,0 +1,291 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 echarts from '../../core/echarts.js';
// import { createHashMap, each, HashMap, hasOwn, keys, map } from 'zrender/lib/core/util.js';
// import SeriesModel from '../../model/Series.js';
// import {
// isCartesian2DDeclaredSeries, findAxisModels, isCartesian2DInjectedAsDataCoordSys
// } from './cartesianAxisHelper.js';
// import { getDataDimensionsOnAxis } from '../axisHelper.js';
// import { AxisBaseModel } from '../AxisBaseModel.js';
// import type Axis from '../Axis.js';
// import GlobalModel from '../../model/Global.js';
// import { Dictionary } from '../../util/types.js';
// import {
// AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM, ensureScaleRawExtentInfo, ScaleRawExtentInfo, ScaleRawExtentResult
// } from '../scaleRawExtentInfo.js';
// import { initExtentForUnion, unionExtentFromNumber } from '../../util/model.js';
/**
* @obsolete
* PENDING:
* - This file is not used anywhere currently.
* - This is a similar behavior to `dataZoom`, but historically supported separately.
* Can it be merged into `dataZoom`?
* - The impl need to be fixed, @see #15050 , and,
* - Remove side-effect.
* - Need to fix the case:
* series_a =>
* x_m (category): dataExtent: [3,8]
* y_i:
* series_b =>
* x_m (category): dataExtent: [4,6]
* y_j:
* series_c =>
* x_m (category): dataExtent: [5,7]
* y_j:
* dataZoom control y_i, so series_a is excluded.
* So x_m.condExtent = [4,6] U [5,7] = [4,7] , and use it to call ensureScaleRawExtentInfo.
* (incorrect?, supposed to be [3,8]?)
*
* See test case `test/axis-filter-extent.html`.
*
* The responsibility of this processor:
* Enable category axis to use the specified `min`/`max` to shrink the extent of the orthogonal axis in
* Cartesian2D. That is, if some data item on a category axis is out of the range of `min`/`max`, the
* extent of the orthogonal axis will exclude the data items.
* A typical case is bar-racing, where bars are sorted dynamically and may only need to
* displayed part of the whole bars.
*
* IMPL_MEMO:
* - For each triple xAxis-yAxis-series, if either xAxis or yAxis is controlled by a dataZoom,
* the triple should be ignored in this processor.
* - Input:
* - Cartesian series data ("series approximate extent" has been prepared).
* - Axis original `ScaleRawExtentInfo`
* (the content comes from ec option and "series approximate extent").
* - Modify(result):
* - `ScaleRawExtentInfo#min/max` of the determined "target axis".
* - "series approximate extent".
*/
// The priority is just after dataZoom processor.
// echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.FILTER + 10, {
// getTargetSeries: function (ecModel) {
// const seriesModelMap = createHashMap<SeriesModel>();
// ecModel.eachSeries(function (seriesModel: SeriesModel) {
// isCartesian2DDeclaredSeries(seriesModel) && seriesModelMap.set(seriesModel.uid, seriesModel);
// });
// return seriesModelMap;
// },
// overallReset: function (ecModel, api) {
// const seriesRecords = [] as SeriesRecord[];
// const axisRecordMap = createHashMap<AxisRecord>();
// prepareDataExtentOnAxis(ecModel, axisRecordMap, seriesRecords);
// calculateFilteredExtent(axisRecordMap, seriesRecords);
// shrinkAxisExtent(axisRecordMap);
// }
// });
// type AxisRecord = {
// rawExtentInfo?: ScaleRawExtentInfo;
// rawExtentResult?: ScaleRawExtentResult;
// tarExtent?: number[];
// };
// type SeriesRecord = {
// seriesModel: SeriesModel;
// xAxisModel: AxisBaseModel;
// yAxisModel: AxisBaseModel;
// };
// function prepareDataExtentOnAxis(
// ecModel: GlobalModel,
// axisRecordMap: HashMap<AxisRecord>,
// seriesRecords: SeriesRecord[]
// ): void {
// ecModel.eachSeries(function (seriesModel: SeriesModel) {
// // If pie (or other similar series) use cartesian2d, the logic below is
// // probably wrong, therefore skip it temporarily.
// // TODO: support union extent in this case.
// // e.g. make a fake seriesData by series.coord/series.center, and it can be
// // performed by data processing (such as, filter), and applied here.
// if (!isCartesian2DInjectedAsDataCoordSys(seriesModel)) {
// return;
// }
// const axesModelMap = findAxisModels(seriesModel);
// const xAxisModel = axesModelMap.xAxisModel;
// const yAxisModel = axesModelMap.yAxisModel;
// const xAxis = xAxisModel.axis;
// const yAxis = yAxisModel.axis;
// const xRawExtentInfo = ensureScaleRawExtentInfo(xAxis);
// const yRawExtentInfo = ensureScaleRawExtentInfo(yAxis);
// // If either axis controlled by other filter like "dataZoom",
// // use the rule of dataZoom rather than adopting the rules here.
// if (
// (xRawExtentInfo && xRawExtentInfo.from === AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM)
// || (yRawExtentInfo && yRawExtentInfo.from === AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM)
// ) {
// return;
// }
// seriesRecords.push({
// seriesModel: seriesModel,
// xAxisModel: xAxisModel,
// yAxisModel: yAxisModel
// });
// });
// }
// function calculateFilteredExtent(
// axisRecordMap: HashMap<AxisRecord>,
// seriesRecords: SeriesRecord[]
// ) {
// each(seriesRecords, function (seriesRecord) {
// const xAxisModel = seriesRecord.xAxisModel;
// const yAxisModel = seriesRecord.yAxisModel;
// const xAxis = xAxisModel.axis;
// const yAxis = yAxisModel.axis;
// const xAxisRecord = prepareAxisRecord(axisRecordMap, xAxisModel);
// const yAxisRecord = prepareAxisRecord(axisRecordMap, yAxisModel);
// xAxisRecord.rawExtentInfo = ensureScaleRawExtentInfo(xAxis);
// yAxisRecord.rawExtentInfo = ensureScaleRawExtentInfo(yAxis);
// xAxisRecord.rawExtentResult = xAxisRecord.rawExtentInfo.calculate();
// yAxisRecord.rawExtentResult = yAxisRecord.rawExtentInfo.calculate();
// const data = seriesRecord.seriesModel.getData();
// // For duplication removal.
// // key: series data dimension corresponding to the condition axis.
// const condDimMap: Dictionary<boolean> = {};
// // key: series data dimension corresponding to the target axis.
// const tarDimMap: Dictionary<boolean> = {};
// let condAxis: Axis;
// let tarAxisRecord: AxisRecord;
// function addCondition(axis: Axis, axisRecord: AxisRecord) {
// // But for simplicity and safety and performance, we only adopt this
// // feature on category axis at present.
// const rawExtentResult = axisRecord.rawExtentResult;
// if (axis.type === 'category'
// && (rawExtentResult.dataMinMax[0] < rawExtentResult.resultMinMax[0]
// || rawExtentResult.resultMinMax[1] < rawExtentResult.dataMinMax[1]
// )
// ) {
// each(getDataDimensionsOnAxis(data, axis.dim), function (dataDim) {
// if (!hasOwn(condDimMap, dataDim)) {
// condDimMap[dataDim] = true;
// condAxis = axis;
// }
// });
// }
// }
// function addTarget(axis: Axis, axisRecord: AxisRecord) {
// const rawExtentResult = axisRecord.rawExtentResult;
// const fixMinMax = rawExtentResult.fixMinMax;
// if (axis.type !== 'category'
// && (!fixMinMax[0] || !fixMinMax[1])
// ) {
// each(getDataDimensionsOnAxis(data, axis.dim), function (dataDim) {
// if (!hasOwn(condDimMap, dataDim) && !hasOwn(tarDimMap, dataDim)) {
// tarDimMap[dataDim] = true;
// tarAxisRecord = axisRecord;
// }
// });
// }
// }
// addCondition(xAxis, xAxisRecord);
// addCondition(yAxis, yAxisRecord);
// addTarget(xAxis, xAxisRecord);
// addTarget(yAxis, yAxisRecord);
// const condDims = keys(condDimMap);
// const tarDims = keys(tarDimMap);
// const tarDimExtents = map(tarDims, function () {
// return initExtentForUnion();
// });
// const condDimsLen = condDims.length;
// const tarDimsLen = tarDims.length;
// if (!condDimsLen || !tarDimsLen) {
// return;
// }
// const singleCondDim = condDimsLen === 1 ? condDims[0] : null;
// const singleTarDim = tarDimsLen === 1 ? tarDims[0] : null;
// const dataLen = data.count();
// // Time consuming, because this is a "block task".
// // Simple optimization for the vast majority of cases.
// if (singleCondDim && singleTarDim) {
// for (let dataIdx = 0; dataIdx < dataLen; dataIdx++) {
// const condVal = data.get(singleCondDim, dataIdx) as number;
// if (condAxis.scale.contain(condVal)) {
// unionExtentFromNumber(tarDimExtents[0], data.get(singleTarDim, dataIdx) as number);
// }
// }
// }
// else {
// for (let dataIdx = 0; dataIdx < dataLen; dataIdx++) {
// for (let j = 0; j < condDimsLen; j++) {
// const condVal = data.get(condDims[j], dataIdx) as number;
// if (condAxis.scale.contain(condVal)) {
// for (let k = 0; k < tarDimsLen; k++) {
// unionExtentFromNumber(tarDimExtents[k], data.get(tarDims[k], dataIdx) as number);
// }
// // Any one dim is in range means satisfied.
// break;
// }
// }
// }
// }
// each(tarDimExtents, function (tarDimExtent, i) {
// // FIXME: if there has been approximateExtent set?
// data.setApproximateExtent(tarDimExtent as [number, number], tarDims[i]);
// const tarAxisExtent = tarAxisRecord.tarExtent = tarAxisRecord.tarExtent || initExtentForUnion();
// unionExtentFromNumber(tarAxisExtent, tarDimExtent[0]);
// unionExtentFromNumber(tarAxisExtent, tarDimExtent[1]);
// });
// });
// }
// function shrinkAxisExtent(axisRecordMap: HashMap<AxisRecord>) {
// axisRecordMap.each(function (axisRecord) {
// const tarAxisExtent = axisRecord.tarExtent;
// if (tarAxisExtent) {
// const rawExtentResult = axisRecord.rawExtentResult;
// const fixMinMax = rawExtentResult.fixMinMax;
// // const rawExtentInfo = axisRecord.rawExtentInfo;
// // Shrink the original extent.
// if (!fixMinMax[0] && tarAxisExtent[0] > rawExtentResult.resultMinMax[0]) {
// // rawExtentInfo.modifyDataMinMax('min', tarAxisExtent[0]);
// }
// if (!fixMinMax[1] && tarAxisExtent[1] < rawExtentResult.resultMinMax[1]) {
// // rawExtentInfo.modifyDataMinMax('max', tarAxisExtent[1]);
// }
// }
// });
// }
// function prepareAxisRecord(
// axisRecordMap: HashMap<AxisRecord>,
// axisModel: AxisBaseModel
// ): AxisRecord {
// return axisRecordMap.get(axisModel.uid)
// || axisRecordMap.set(axisModel.uid, {});
// }
+121
View File
@@ -0,0 +1,121 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 BoundingRect from 'zrender/lib/core/BoundingRect.js';
import { each } from 'zrender/lib/core/util.js';
import { registerLegacyGridContainLabelImpl } from './Grid.js';
import OrdinalScale from '../../scale/Ordinal.js';
import { makeLabelFormatter } from '../axisHelper.js';
/**
* [CAUTION] Never export methods other than `installLegacyGridContainLabel`.
*/
export function installLegacyGridContainLabel() {
registerLegacyGridContainLabelImpl(legacyLayOutGridByContained);
}
/**
* The input gridRect and axes will be modified.
*/
function legacyLayOutGridByContained(axesList, gridRect) {
each(axesList, function (axis) {
if (!axis.model.get(['axisLabel', 'inside'])) {
var labelUnionRect = estimateLabelUnionRect(axis);
if (labelUnionRect) {
var dim = axis.isHorizontal() ? 'height' : 'width';
var margin = axis.model.get(['axisLabel', 'margin']);
gridRect[dim] -= labelUnionRect[dim] + margin;
if (axis.position === 'top') {
gridRect.y += labelUnionRect.height + margin;
} else if (axis.position === 'left') {
gridRect.x += labelUnionRect.width + margin;
}
}
}
});
}
/**
* @return Be null/undefined if no labels.
*/
function estimateLabelUnionRect(axis) {
var axisModel = axis.model;
var scale = axis.scale;
if (!axisModel.get(['axisLabel', 'show']) || scale.isBlank()) {
return;
}
var realNumberScaleTicks;
var tickCount;
var categoryScaleExtent = scale.getExtent();
// Optimize for large category data, avoid call `getTicks()`.
if (scale instanceof OrdinalScale) {
tickCount = scale.count();
} else {
realNumberScaleTicks = scale.getTicks();
tickCount = realNumberScaleTicks.length;
}
var axisLabelModel = axis.getLabelModel();
var labelFormatter = makeLabelFormatter(axis);
var rect;
var step = 1;
// Simple optimization for large amount of category labels
if (tickCount > 40) {
step = Math.ceil(tickCount / 40);
}
for (var i = 0; i < tickCount; i += step) {
var tick = realNumberScaleTicks ? realNumberScaleTicks[i] : {
value: categoryScaleExtent[0] + i
};
var label = labelFormatter(tick, i);
var unrotatedSingleRect = axisLabelModel.getTextRect(label);
var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);
rect ? rect.union(singleRect) : rect = singleRect;
}
return rect;
function rotateTextRect(textRect, rotate) {
var rotateRadians = rotate * Math.PI / 180;
var beforeWidth = textRect.width;
var beforeHeight = textRect.height;
var afterWidth = beforeWidth * Math.abs(Math.cos(rotateRadians)) + Math.abs(beforeHeight * Math.sin(rotateRadians));
var afterHeight = beforeWidth * Math.abs(Math.sin(rotateRadians)) + Math.abs(beforeHeight * Math.cos(rotateRadians));
var rotatedRect = new BoundingRect(textRect.x, textRect.y, afterWidth, afterHeight);
return rotatedRect;
}
}
+75
View File
@@ -0,0 +1,75 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import { calcBandWidth } from '../axisBand.js';
function dataToCoordSize(dataSize, dataItem) {
// dataItem is necessary in log axis.
dataItem = dataItem || [0, 0];
return zrUtil.map(['x', 'y'], function (dim, dimIdx) {
var axis = this.getAxis(dim);
var val = dataItem[dimIdx];
var halfSize = dataSize[dimIdx] / 2;
return axis.type === 'category' ? calcBandWidth(axis).w : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));
}, this);
}
export default function cartesianPrepareCustom(coordSys) {
var rect = coordSys.master.getRect();
return {
coordSys: {
// The name exposed to user is always 'cartesian2d' but not 'grid'.
type: 'cartesian2d',
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height
},
api: {
coord: function (data) {
// do not provide "out" param
return coordSys.dataToPoint(data);
},
size: zrUtil.bind(dataToCoordSize, coordSys)
}
};
}
+219
View File
@@ -0,0 +1,219 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import View, { useLegacyViewCoordSysCenterBase, viewCoordSysCopyViewRect, viewCoordSysSetBoundingRect } from '../View.js';
import geoSourceManager from './geoSourceManager.js';
import { SINGLE_REFERRING } from '../../util/model.js';
import { warn } from '../../util/log.js';
import Transformable from 'zrender/lib/core/Transformable.js';
var GEO_DEFAULT_PARAMS = {
'geoJSON': {
aspectScale: 0.75,
invertLongitute: true
},
'geoSVG': {
aspectScale: 1,
invertLongitute: false
}
};
export var geo2DDimensions = ['lng', 'lat'];
var Geo = /** @class */function (_super) {
__extends(Geo, _super); // See VIEW_COORD_SYS_TRANS_OVERALL_BACKWARD_COMPATIBILITY
function Geo(name, map, opt) {
var _this = _super.call(this) || this;
_this.dimensions = geo2DDimensions;
_this.type = 'geo';
// Only store specified name coord via `addGeoCoord`.
_this._nameCoordMap = zrUtil.createHashMap();
_this.name = name;
var projection = opt.projection;
var source = geoSourceManager.load(map, opt.nameMap, opt.nameProperty);
var resource = geoSourceManager.getGeoResource(map);
var resourceType = _this.resourceType = resource ? resource.type : null;
var regions = _this.regions = source.regions;
var defaultParams = GEO_DEFAULT_PARAMS[resource.type];
_this._clip = opt.clip;
// Not invert longitude if projection exits.
var invertLongitute = projection ? false : defaultParams.invertLongitute;
_this.view = new View(invertLongitute, useLegacyViewCoordSysCenterBase(opt.ecModel, opt.api), _this);
_this.map = map;
_this._regionsMap = source.regionsMap;
_this.regions = source.regions;
if (process.env.NODE_ENV !== 'production' && projection) {
// Do some check
if (resourceType === 'geoSVG') {
if (process.env.NODE_ENV !== 'production') {
warn("Map " + map + " with SVG source can't use projection. Only GeoJSON source supports projection.");
}
projection = null;
}
if (!(projection.project && projection.unproject)) {
if (process.env.NODE_ENV !== 'production') {
warn('project and unproject must be both provided in the projeciton.');
}
projection = null;
}
}
_this.projection = projection;
var boundingRect;
if (projection) {
// Can't reuse the raw bounding rect
for (var i = 0; i < regions.length; i++) {
var regionRect = regions[i].getBoundingRect(projection);
boundingRect = boundingRect || regionRect.clone();
boundingRect.union(regionRect);
}
} else {
boundingRect = source.boundingRect;
}
viewCoordSysSetBoundingRect(_this.view, boundingRect.x, boundingRect.y, boundingRect.width, boundingRect.height);
// aspectScale and invertLongitute actually is the parameters default raw projection.
// So we ignore them if projection is given.
// Ignore default aspect scale if projection exits.
_this.aspectScale = projection ? 1 : zrUtil.retrieve2(opt.aspectScale, defaultParams.aspectScale);
return _this;
}
Geo.prototype.getRegion = function (name) {
return this._regionsMap.get(name);
};
Geo.prototype.getRegionByCoord = function (coord) {
var regions = this.regions;
for (var i = 0; i < regions.length; i++) {
var region = regions[i];
if (region.type === 'geoJSON' && region.contain(coord)) {
return regions[i];
}
}
};
/**
* Add geoCoord for indexing by name
*/
Geo.prototype.addGeoCoord = function (name, geoCoord) {
this._nameCoordMap.set(name, geoCoord);
};
/**
* Get geoCoord by name
*/
Geo.prototype.getGeoCoord = function (name) {
var region = this._regionsMap.get(name);
// Calculate center only on demand.
return this._nameCoordMap.get(name) || region && region.getCenter();
};
Geo.prototype.dataToPoint = function (data, noRoam, out) {
if (zrUtil.isString(data)) {
// Map area name to geoCoord
data = this.getGeoCoord(data);
}
if (data) {
var projection = this.projection;
if (projection) {
// projection may return null point.
data = projection.project(data);
}
return data && this.view.dataToPoint(data, noRoam, out);
}
};
Geo.prototype.pointToData = function (point, reserved, out) {
var projection = this.projection;
if (projection) {
// projection may return null point.
point = projection.unproject(point);
}
// FIXME: if no `point`, should return [NaN, NaN], rather than undefined.
// null/undefined has special meaning in `convertFromPixel`.
return point && this.view.pointToData(point, out);
};
Geo.prototype.convertToPixel = function (ecModel, finder, value) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.dataToPoint(value) : null;
};
Geo.prototype.convertFromPixel = function (ecModel, finder, pixel) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.pointToData(pixel) : null;
};
Geo.prototype.containPoint = function (point) {
return this.view.containPoint(point);
};
Geo.prototype.getArea = function (tolerance) {
tolerance = tolerance || 0;
var rect = viewCoordSysCopyViewRect(null, this.view);
rect.x -= tolerance;
rect.y -= tolerance;
rect.width += 2 * tolerance;
rect.height += 2 * tolerance;
return rect;
};
Geo.prototype.shouldClip = function () {
return this._clip;
};
/**
* @implements CoordinateSystem['getBoundingRect']
*/
Geo.prototype.getBoundingRect = function () {
return this.view.getBoundingRect();
};
/**
* @implements CoordinateSystem['getViewRect']
*/
Geo.prototype.getViewRect = function () {
return this.view.getViewRect();
};
/**
* @implements CoordinateSystem['getRoamTransform']
*/
Geo.prototype.getRoamTransform = function () {
return this.view.getRoamTransform();
};
return Geo;
}(Transformable // See VIEW_COORD_SYS_TRANS_OVERALL_BACKWARD_COMPATIBILITY
);
;
function getCoordSys(finder) {
var geoModel = finder.geoModel;
var seriesModel = finder.seriesModel;
return geoModel ? geoModel.coordinateSystem : seriesModel ? seriesModel.coordinateSystem // For map series.
|| (seriesModel.getReferringComponents('geo', SINGLE_REFERRING).models[0] || {}).coordinateSystem : null;
}
export default Geo;
+144
View File
@@ -0,0 +1,144 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { each, isString, createHashMap, hasOwn } from 'zrender/lib/core/util.js';
import parseGeoJson from './parseGeoJson.js';
// Built-in GEO fixer.
import fixNanhai from './fix/nanhai.js';
import fixTextCoord from './fix/textCoord.js';
import fixDiaoyuIsland from './fix/diaoyuIsland.js';
import BoundingRect from 'zrender/lib/core/BoundingRect.js';
var DEFAULT_NAME_PROPERTY = 'name';
var GeoJSONResource = /** @class */function () {
function GeoJSONResource(mapName, geoJSON, specialAreas) {
this.type = 'geoJSON';
this._parsedMap = createHashMap();
this._mapName = mapName;
this._specialAreas = specialAreas;
// PENDING: delay the parse to the first usage to rapid up the FMP?
this._geoJSON = parseInput(geoJSON);
}
/**
* @param nameMap can be null/undefined
* @param nameProperty can be null/undefined
*/
GeoJSONResource.prototype.load = function (nameMap, nameProperty) {
nameProperty = nameProperty || DEFAULT_NAME_PROPERTY;
var parsed = this._parsedMap.get(nameProperty);
if (!parsed) {
var rawRegions = this._parseToRegions(nameProperty);
parsed = this._parsedMap.set(nameProperty, {
regions: rawRegions,
boundingRect: calculateBoundingRect(rawRegions)
});
}
var regionsMap = createHashMap();
var finalRegions = [];
each(parsed.regions, function (region) {
var regionName = region.name;
// Try use the alias in geoNameMap
if (nameMap && hasOwn(nameMap, regionName)) {
region = region.cloneShallow(regionName = nameMap[regionName]);
}
finalRegions.push(region);
regionsMap.set(regionName, region);
});
return {
regions: finalRegions,
boundingRect: parsed.boundingRect || new BoundingRect(0, 0, 0, 0),
regionsMap: regionsMap
};
};
GeoJSONResource.prototype._parseToRegions = function (nameProperty) {
var mapName = this._mapName;
var geoJSON = this._geoJSON;
var rawRegions;
// https://jsperf.com/try-catch-performance-overhead
try {
rawRegions = geoJSON ? parseGeoJson(geoJSON, nameProperty) : [];
} catch (e) {
throw new Error('Invalid geoJson format\n' + e.message);
}
fixNanhai(mapName, rawRegions);
each(rawRegions, function (region) {
var regionName = region.name;
fixTextCoord(mapName, region);
fixDiaoyuIsland(mapName, region);
// Some area like Alaska in USA map needs to be tansformed
// to look better
var specialArea = this._specialAreas && this._specialAreas[regionName];
if (specialArea) {
region.transformTo(specialArea.left, specialArea.top, specialArea.width, specialArea.height);
}
}, this);
return rawRegions;
};
/**
* Only for exporting to users.
* **MUST NOT** used internally.
*/
GeoJSONResource.prototype.getMapForUser = function () {
return {
// For backward compatibility, use geoJson
// PENDING: it has been returning them without clone.
// do we need to avoid outsite modification?
geoJson: this._geoJSON,
geoJSON: this._geoJSON,
specialAreas: this._specialAreas
};
};
return GeoJSONResource;
}();
export { GeoJSONResource };
function calculateBoundingRect(regions) {
var rect;
for (var i = 0; i < regions.length; i++) {
var regionRect = regions[i].getBoundingRect();
rect = rect || regionRect.clone();
rect.union(regionRect);
}
return rect;
}
function parseInput(source) {
return !isString(source) ? source : typeof JSON !== 'undefined' && JSON.parse ? JSON.parse(source) : new Function('return (' + source + ');')();
}
+204
View File
@@ -0,0 +1,204 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import * as modelUtil from '../../util/model.js';
import ComponentModel from '../../model/Component.js';
import Model from '../../model/Model.js';
import geoCreator from './geoCreator.js';
import geoSourceManager from './geoSourceManager.js';
import tokens from '../../visual/tokens.js';
;
var GeoModel = /** @class */function (_super) {
__extends(GeoModel, _super);
function GeoModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = GeoModel.type;
return _this;
}
GeoModel.prototype.init = function (option, parentModel, ecModel) {
this.mergeDefaultAndTheme(option, ecModel);
var source = geoSourceManager.getGeoResource(option.map);
if (source && source.type === 'geoJSON') {
var itemStyle = option.itemStyle = option.itemStyle || {};
if (!('color' in itemStyle)) {
itemStyle.color = option.defaultItemStyleColor || tokens.color.backgroundTint;
}
}
// Default label emphasis `show`
modelUtil.defaultEmphasis(option, 'label', ['show']);
};
GeoModel.prototype.optionUpdated = function () {
var _this = this;
var option = this.option;
option.regions = geoCreator.getFilledRegions(option.regions, option.map, option.nameMap, option.nameProperty);
var selectedMap = {};
this._optionModelMap = zrUtil.reduce(option.regions || [], function (optionModelMap, regionOpt) {
var 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.
*/
GeoModel.prototype.getRegionModel = function (name) {
return this._optionModelMap.get(name) || new Model(null, this, this.ecModel);
};
/**
* Format label
* @param name Region name
*/
GeoModel.prototype.getFormattedLabel = function (name, status) {
var regionModel = this.getRegionModel(name);
var formatter = status === 'normal' ? regionModel.get(['label', 'formatter']) : regionModel.get(['emphasis', 'label', 'formatter']);
var params = {
name: name
};
if (zrUtil.isFunction(formatter)) {
params.status = status;
return formatter(params);
} else if (zrUtil.isString(formatter)) {
return formatter.replace('{a}', name != null ? name : '');
}
};
// PENGING If selectedMode is null ?
GeoModel.prototype.select = function (name) {
var option = this.option;
var selectedMode = option.selectedMode;
if (!selectedMode) {
return;
}
if (selectedMode !== 'multiple') {
option.selectedMap = null;
}
var selectedMap = option.selectedMap || (option.selectedMap = {});
selectedMap[name] = true;
};
GeoModel.prototype.unSelect = function (name) {
var selectedMap = this.option.selectedMap;
if (selectedMap) {
selectedMap[name] = false;
}
};
GeoModel.prototype.toggleSelected = function (name) {
this[this.isSelected(name) ? 'unSelect' : 'select'](name);
};
GeoModel.prototype.isSelected = function (name) {
var selectedMap = this.option.selectedMap;
return !!(selectedMap && selectedMap[name]);
};
GeoModel.prototype.__ownRoamView = function () {
return this.coordinateSystem.view;
};
GeoModel.type = 'geo';
GeoModel.layoutMode = 'box';
GeoModel.defaultOption = {
// 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 want to put map in a fixed size box with right aspect ratio
// This two properties may be more convenient
// 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: tokens.color.tertiary
},
itemStyle: {
borderWidth: 0.5,
borderColor: tokens.color.border
},
emphasis: {
label: {
show: true,
color: tokens.color.primary
},
itemStyle: {
color: tokens.color.highlight
}
},
select: {
label: {
show: true,
color: tokens.color.primary
},
itemStyle: {
color: tokens.color.highlight
}
},
regions: []
// tooltip: {
// show: false
// }
};
return GeoModel;
}(ComponentModel);
export default GeoModel;
+333
View File
@@ -0,0 +1,333 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/tool/parseSVG.js';
import Group from 'zrender/lib/graphic/Group.js';
import Rect from 'zrender/lib/graphic/shape/Rect.js';
import { assert, createHashMap, each } from 'zrender/lib/core/util.js';
import BoundingRect from 'zrender/lib/core/BoundingRect.js';
import { parseXML } from 'zrender/lib/tool/parseXML.js';
import { GeoSVGRegion } from './Region.js';
/**
* "region available" means that: enable users to set attribute `name="xxx"` on those tags
* to make it be a region.
* 1. region styles and its label styles can be defined in echarts opton:
* ```js
* geo: {
* regions: [{
* name: 'xxx',
* itemStyle: { ... },
* label: { ... }
* }, {
* ...
* },
* ...]
* };
* ```
* 2. name can be duplicated in different SVG tag. All of the tags with the same name share
* a region option. For exampel if there are two <path> representing two lung lobes. They have
* no common parents but both of them need to display label "lung" inside.
*/
var REGION_AVAILABLE_SVG_TAG_MAP = createHashMap(['rect', 'circle', 'line', 'ellipse', 'polygon', 'polyline', 'path',
// <text> <tspan> are also enabled because some SVG might paint text itself,
// but still need to trigger events or tooltip.
'text', 'tspan',
// <g> is also enabled because this case: if multiple tags share one name
// and need label displayed, every tags will display the name, which is not
// expected. So we can put them into a <g name="xxx">. Thereby only one label
// displayed and located based on the bounding rect of the <g>.
'g']);
var GeoSVGResource = /** @class */function () {
function GeoSVGResource(mapName, svg) {
this.type = 'geoSVG';
// All used graphics. key: hostKey, value: root
this._usedGraphicMap = createHashMap();
// All unused graphics.
this._freedGraphics = [];
this._mapName = mapName;
// Only perform parse to XML object here, which might be time
// consiming for large SVG.
// Although convert XML to zrender element is also time consiming,
// if we do it here, the clone of zrender elements has to be
// required. So we do it once for each geo instance, util real
// performance issues call for optimizing it.
this._parsedXML = parseXML(svg);
}
GeoSVGResource.prototype.load = function /* nameMap: NameMap */
() {
// In the "load" stage, graphic need to be built to
// get boundingRect for geo coordinate system.
var firstGraphic = this._firstGraphic;
// Create the return data structure only when first graphic created.
// Because they will be used in geo coordinate system update stage,
// and `regions` will be mounted at `geo` coordinate system,
// in which there is no "view" info, so that it should better not to
// make references to graphic elements.
if (!firstGraphic) {
firstGraphic = this._firstGraphic = this._buildGraphic(this._parsedXML);
this._freedGraphics.push(firstGraphic);
this._boundingRect = this._firstGraphic.boundingRect.clone();
// PENDING: `nameMap` will not be supported until some real requirement come.
// if (nameMap) {
// named = applyNameMap(named, nameMap);
// }
var _a = createRegions(firstGraphic.named),
regions = _a.regions,
regionsMap = _a.regionsMap;
this._regions = regions;
this._regionsMap = regionsMap;
}
return {
boundingRect: this._boundingRect,
regions: this._regions,
regionsMap: this._regionsMap
};
};
GeoSVGResource.prototype._buildGraphic = function (svgXML) {
var result;
var rootFromParse;
try {
result = svgXML && parseSVG(svgXML, {
ignoreViewBox: true,
ignoreRootClip: true
}) || {};
rootFromParse = result.root;
assert(rootFromParse != null);
} catch (e) {
throw new Error('Invalid svg format\n' + e.message);
}
// Note: we keep the covenant that the root has no transform. So always add an extra root.
var root = new Group();
root.add(rootFromParse);
root.isGeoSVGGraphicRoot = true;
// [THE_RULE_OF_VIEWPORT_AND_VIEWBOX]
//
// Consider: `<svg width="..." height="..." viewBox="...">`
// - the `width/height` we call it `svgWidth/svgHeight` for short.
// - `(0, 0, svgWidth, svgHeight)` defines the viewport of the SVG, or say,
// "viewport boundingRect", or `boundingRect` for short.
// - `viewBox` defines the transform from the real content ot the viewport.
// `viewBox` has the same unit as the content of SVG.
// If `viewBox` exists, a transform is defined, so the unit of `svgWidth/svgHeight` become
// different from the content of SVG. Otherwise, they are the same.
//
// If both `svgWidth/svgHeight/viewBox` are specified in a SVG file, the transform rule will be:
// 0. `boundingRect` is `(0, 0, svgWidth, svgHeight)`. Set it to Geo['_rect'] (View['_rect']).
// 1. Make a transform from `viewBox` to `boundingRect`.
// Note: only support `preserveAspectRatio 'xMidYMid'` here. That is, this transform will preserve
// the aspect ratio.
// 2. Make a transform from boundingRect to Geo['_viewRect'] (View['_viewRect'])
// (`Geo`/`View` will do this job).
// Note: this transform might not preserve aspect radio, which depending on how users specify
// viewRect in echarts option (e.g., `geo.left/top/width/height` will not preserve aspect ratio,
// but `geo.layoutCenter/layoutSize` will preserve aspect ratio).
//
// If `svgWidth/svgHeight` not specified, we use `viewBox` as the `boundingRect` to make the SVG
// layout look good.
//
// If neither `svgWidth/svgHeight` nor `viewBox` are not specified, we calculate the boundingRect
// of the SVG content and use them to make SVG layout look good.
var svgWidth = result.width;
var svgHeight = result.height;
var viewBoxRect = result.viewBoxRect;
var boundingRect = this._boundingRect;
if (!boundingRect) {
var bRectX = void 0;
var bRectY = void 0;
var bRectWidth = void 0;
var bRectHeight = void 0;
if (svgWidth != null) {
bRectX = 0;
bRectWidth = svgWidth;
} else if (viewBoxRect) {
bRectX = viewBoxRect.x;
bRectWidth = viewBoxRect.width;
}
if (svgHeight != null) {
bRectY = 0;
bRectHeight = svgHeight;
} else if (viewBoxRect) {
bRectY = viewBoxRect.y;
bRectHeight = viewBoxRect.height;
}
// If both viewBox and svgWidth/svgHeight not specified,
// we have to determine how to layout those element to make them look good.
if (bRectX == null || bRectY == null) {
var calculatedBoundingRect = rootFromParse.getBoundingRect();
if (bRectX == null) {
bRectX = calculatedBoundingRect.x;
bRectWidth = calculatedBoundingRect.width;
}
if (bRectY == null) {
bRectY = calculatedBoundingRect.y;
bRectHeight = calculatedBoundingRect.height;
}
}
boundingRect = this._boundingRect = new BoundingRect(bRectX, bRectY, bRectWidth, bRectHeight);
}
if (viewBoxRect) {
var viewBoxTransform = makeViewBoxTransform(viewBoxRect, boundingRect);
// Only support `preserveAspectRatio 'xMidYMid'`
rootFromParse.scaleX = rootFromParse.scaleY = viewBoxTransform.scale;
rootFromParse.x = viewBoxTransform.x;
rootFromParse.y = viewBoxTransform.y;
}
// SVG needs to clip based on `viewBox`. And some SVG files really rely on this feature.
// They do not strictly confine all of the content inside a display rect, but deliberately
// use a `viewBox` to define a displayable rect.
// PENDING:
// The drawback of the `setClipPath` here is: the region label (genereted by echarts) near the
// edge might also be clipped, because region labels are put as `textContent` of the SVG path.
root.setClipPath(new Rect({
shape: boundingRect.plain()
}));
var named = [];
each(result.named, function (namedItem) {
if (REGION_AVAILABLE_SVG_TAG_MAP.get(namedItem.svgNodeTagLower) != null) {
named.push(namedItem);
setSilent(namedItem.el);
}
});
return {
root: root,
boundingRect: boundingRect,
named: named
};
};
/**
* Consider:
* (1) One graphic element can not be shared by different `geoView` running simultaneously.
* Notice, also need to consider multiple echarts instances share a `mapRecord`.
* (2) Converting SVG to graphic elements is time consuming.
* (3) In the current architecture, `load` should be called frequently to get boundingRect,
* and it is called without view info.
* So we maintain graphic elements in this module, and enables `view` to use/return these
* graphics from/to the pool with it's uid.
*/
GeoSVGResource.prototype.useGraphic = function (hostKey /* , nameMap: NameMap */) {
var usedRootMap = this._usedGraphicMap;
var svgGraphic = usedRootMap.get(hostKey);
if (svgGraphic) {
return svgGraphic;
}
svgGraphic = this._freedGraphics.pop()
// use the first boundingRect to avoid duplicated boundingRect calculation.
|| this._buildGraphic(this._parsedXML);
usedRootMap.set(hostKey, svgGraphic);
// PENDING: `nameMap` will not be supported until some real requirement come.
// `nameMap` can only be obtained from echarts option.
// The original `named` must not be modified.
// if (nameMap) {
// svgGraphic = extend({}, svgGraphic);
// svgGraphic.named = applyNameMap(svgGraphic.named, nameMap);
// }
return svgGraphic;
};
GeoSVGResource.prototype.freeGraphic = function (hostKey) {
var usedRootMap = this._usedGraphicMap;
var svgGraphic = usedRootMap.get(hostKey);
if (svgGraphic) {
usedRootMap.removeKey(hostKey);
this._freedGraphics.push(svgGraphic);
}
};
return GeoSVGResource;
}();
export { GeoSVGResource };
function setSilent(el) {
// Only named element has silent: false, other elements should
// act as background and has no user interaction.
el.silent = false;
// text|tspan will be converted to group.
if (el.isGroup) {
el.traverse(function (child) {
child.silent = false;
});
}
}
function createRegions(named) {
var regions = [];
var regionsMap = createHashMap();
// Create resions only for the first graphic.
each(named, function (namedItem) {
// Region has feature to calculate center for tooltip or other features.
// If there is a <g name="xxx">, the center should be the center of the
// bounding rect of the g.
if (namedItem.namedFrom != null) {
return;
}
var region = new GeoSVGRegion(namedItem.name, namedItem.el);
// PENDING: if `nameMap` supported, this region can not be mounted on
// `this`, but can only be created each time `load()` called.
regions.push(region);
// PENDING: if multiple tag named with the same name, only one will be
// found by `_regionsMap`. `_regionsMap` is used to find a coordinate
// by name. We use `region.getCenter()` as the coordinate.
regionsMap.set(namedItem.name, region);
});
return {
regions: regions,
regionsMap: regionsMap
};
}
// PENDING: `nameMap` will not be supported until some real requirement come.
// /**
// * Use the alias in geoNameMap.
// * The input `named` must not be modified.
// */
// function applyNameMap(
// named: GeoSVGGraphicRecord['named'],
// nameMap: NameMap
// ): GeoSVGGraphicRecord['named'] {
// const result = [] as GeoSVGGraphicRecord['named'];
// for (let i = 0; i < named.length; i++) {
// let regionGraphic = named[i];
// const name = regionGraphic.name;
// if (nameMap && nameMap.hasOwnProperty(name)) {
// regionGraphic = extend({}, regionGraphic);
// regionGraphic.name = name;
// }
// result.push(regionGraphic);
// }
// return result;
// }
+286
View File
@@ -0,0 +1,286 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import BoundingRect from 'zrender/lib/core/BoundingRect.js';
import * as vec2 from 'zrender/lib/core/vector.js';
import * as polygonContain from 'zrender/lib/contain/polygon.js';
import * as matrix from 'zrender/lib/core/matrix.js';
import { each } from 'zrender/lib/core/util.js';
var TMP_TRANSFORM = [];
function transformPoints(points, transform) {
for (var p = 0; p < points.length; p++) {
vec2.applyTransform(points[p], points[p], transform);
}
}
function updateBBoxFromPoints(points, min, max, projection) {
for (var i = 0; i < points.length; i++) {
var p = points[i];
if (projection) {
// projection may return null point.
p = projection.project(p);
}
if (p && isFinite(p[0]) && isFinite(p[1])) {
vec2.min(min, min, p);
vec2.max(max, max, p);
}
}
}
function centroid(points) {
var signedArea = 0;
var cx = 0;
var cy = 0;
var len = points.length;
var x0 = points[len - 1][0];
var y0 = points[len - 1][1];
// Polygon should been closed.
for (var i = 0; i < len; i++) {
var x1 = points[i][0];
var y1 = points[i][1];
var a = x0 * y1 - x1 * y0;
signedArea += a;
cx += (x0 + x1) * a;
cy += (y0 + y1) * a;
x0 = x1;
y0 = y1;
}
return signedArea ? [cx / signedArea / 3, cy / signedArea / 3, signedArea] : [points[0][0] || 0, points[0][1] || 0];
}
var Region = /** @class */function () {
function Region(name) {
this.name = name;
}
Region.prototype.setCenter = function (center) {
this._center = center;
};
/**
* Get center point in data unit. That is,
* for GeoJSONRegion, the unit is lat/lng,
* for GeoSVGRegion, the unit is SVG local coord.
*/
Region.prototype.getCenter = function () {
var center = this._center;
if (!center) {
// In most cases there are no need to calculate this center.
// So calculate only when called.
center = this._center = this.calcCenter();
}
return center;
};
return Region;
}();
export { Region };
var GeoJSONPolygonGeometry = /** @class */function () {
function GeoJSONPolygonGeometry(exterior, interiors) {
this.type = 'polygon';
this.exterior = exterior;
this.interiors = interiors;
}
return GeoJSONPolygonGeometry;
}();
export { GeoJSONPolygonGeometry };
var GeoJSONLineStringGeometry = /** @class */function () {
function GeoJSONLineStringGeometry(points) {
this.type = 'linestring';
this.points = points;
}
return GeoJSONLineStringGeometry;
}();
export { GeoJSONLineStringGeometry };
var GeoJSONRegion = /** @class */function (_super) {
__extends(GeoJSONRegion, _super);
function GeoJSONRegion(name, geometries, cp) {
var _this = _super.call(this, name) || this;
_this.type = 'geoJSON';
_this.geometries = geometries;
_this._center = cp && [cp[0], cp[1]];
return _this;
}
GeoJSONRegion.prototype.calcCenter = function () {
var geometries = this.geometries;
var largestGeo;
var largestGeoSize = 0;
for (var i = 0; i < geometries.length; i++) {
var geo = geometries[i];
var exterior = geo.exterior;
// Simple trick to use points count instead of polygon area as region size.
// Ignore linestring
var size = exterior && exterior.length;
if (size > largestGeoSize) {
largestGeo = geo;
largestGeoSize = size;
}
}
if (largestGeo) {
return centroid(largestGeo.exterior);
}
// from bounding rect by default.
var rect = this.getBoundingRect();
return [rect.x + rect.width / 2, rect.y + rect.height / 2];
};
GeoJSONRegion.prototype.getBoundingRect = function (projection) {
var rect = this._rect;
// Always recalculate if using projection.
if (rect && !projection) {
return rect;
}
var min = [Infinity, Infinity];
var max = [-Infinity, -Infinity];
var geometries = this.geometries;
each(geometries, function (geo) {
if (geo.type === 'polygon') {
// Doesn't consider hole
updateBBoxFromPoints(geo.exterior, min, max, projection);
} else {
each(geo.points, function (points) {
updateBBoxFromPoints(points, min, max, projection);
});
}
});
// Normalie invalid bounding.
if (!(isFinite(min[0]) && isFinite(min[1]) && isFinite(max[0]) && isFinite(max[1]))) {
min[0] = min[1] = max[0] = max[1] = 0;
}
rect = new BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]);
if (!projection) {
this._rect = rect;
}
return rect;
};
GeoJSONRegion.prototype.contain = function (coord) {
var rect = this.getBoundingRect();
var geometries = this.geometries;
if (!rect.contain(coord[0], coord[1])) {
return false;
}
loopGeo: for (var i = 0, len = geometries.length; i < len; i++) {
var geo = geometries[i];
// Only support polygon.
if (geo.type !== 'polygon') {
continue;
}
var exterior = geo.exterior;
var interiors = geo.interiors;
if (polygonContain.contain(exterior, coord[0], coord[1])) {
// Not in the region if point is in the hole.
for (var k = 0; k < (interiors ? interiors.length : 0); k++) {
if (polygonContain.contain(interiors[k], coord[0], coord[1])) {
continue loopGeo;
}
}
return true;
}
}
return false;
};
/**
* Transform the raw coords to target bounding.
* @param x
* @param y
* @param width
* @param height
*/
GeoJSONRegion.prototype.transformTo = function (x, y, width, height) {
var rect = this.getBoundingRect();
var aspect = rect.width / rect.height;
if (!width) {
width = aspect * height;
} else if (!height) {
height = width / aspect;
}
var target = new BoundingRect(x, y, width, height);
var transform = rect.calculateTransform(target);
var geometries = this.geometries;
for (var i = 0; i < geometries.length; i++) {
var geo = geometries[i];
if (geo.type === 'polygon') {
transformPoints(geo.exterior, transform);
each(geo.interiors, function (interior) {
transformPoints(interior, transform);
});
} else {
each(geo.points, function (points) {
transformPoints(points, transform);
});
}
}
rect = this._rect;
rect.copy(target);
// Update center
this._center = [rect.x + rect.width / 2, rect.y + rect.height / 2];
};
GeoJSONRegion.prototype.cloneShallow = function (name) {
name == null && (name = this.name);
var newRegion = new GeoJSONRegion(name, this.geometries, this._center);
newRegion._rect = this._rect;
newRegion.transformTo = null; // Simply avoid to be called.
return newRegion;
};
return GeoJSONRegion;
}(Region);
export { GeoJSONRegion };
var GeoSVGRegion = /** @class */function (_super) {
__extends(GeoSVGRegion, _super);
function GeoSVGRegion(name, elOnlyForCalculate) {
var _this = _super.call(this, name) || this;
_this.type = 'geoSVG';
_this._elOnlyForCalculate = elOnlyForCalculate;
return _this;
}
GeoSVGRegion.prototype.calcCenter = function () {
var el = this._elOnlyForCalculate;
var rect = el.getBoundingRect();
var center = [rect.x + rect.width / 2, rect.y + rect.height / 2];
var mat = matrix.identity(TMP_TRANSFORM);
var target = el;
while (target && !target.isGeoSVGGraphicRoot) {
matrix.mul(mat, target.getLocalTransform(), mat);
target = target.parent;
}
matrix.invert(mat, mat);
vec2.applyTransform(center, center, mat);
return center;
};
return GeoSVGRegion;
}(Region);
export { GeoSVGRegion };
+56
View File
@@ -0,0 +1,56 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
// Fix for 钓鱼岛
// let Region = require('../Region');
// let zrUtil = require('zrender/lib/core/util');
// let geoCoord = [126, 25];
var points = [[[123.45165252685547, 25.73527164402261], [123.49731445312499, 25.73527164402261], [123.49731445312499, 25.750734064600884], [123.45165252685547, 25.750734064600884], [123.45165252685547, 25.73527164402261]]];
export default function fixDiaoyuIsland(mapType, region) {
if (mapType === 'china' && region.name === '台湾') {
region.geometries.push({
type: 'polygon',
exterior: points[0]
});
}
}
+57
View File
@@ -0,0 +1,57 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 geoCoordMap = {
'Russia': [100, 60],
'United States': [-99, 38],
'United States of America': [-99, 38]
};
export default function fixGeoCoords(mapType, region) {
if (mapType === 'world') {
var geoCoord = geoCoordMap[region.name];
if (geoCoord) {
var cp = [geoCoord[0], geoCoord[1]];
region.setCenter(cp);
}
}
}
+73
View File
@@ -0,0 +1,73 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
// Fix for 南海诸岛
import * as zrUtil from 'zrender/lib/core/util.js';
import { GeoJSONRegion } from '../Region.js';
var geoCoord = [126, 25];
var nanhaiName = '南海诸岛';
var points = [[[0, 3.5], [7, 11.2], [15, 11.9], [30, 7], [42, 0.7], [52, 0.7], [56, 7.7], [59, 0.7], [64, 0.7], [64, 0], [5, 0], [0, 3.5]], [[13, 16.1], [19, 14.7], [16, 21.7], [11, 23.1], [13, 16.1]], [[12, 32.2], [14, 38.5], [15, 38.5], [13, 32.2], [12, 32.2]], [[16, 47.6], [12, 53.2], [13, 53.2], [18, 47.6], [16, 47.6]], [[6, 64.4], [8, 70], [9, 70], [8, 64.4], [6, 64.4]], [[23, 82.6], [29, 79.8], [30, 79.8], [25, 82.6], [23, 82.6]], [[37, 70.7], [43, 62.3], [44, 62.3], [39, 70.7], [37, 70.7]], [[48, 51.1], [51, 45.5], [53, 45.5], [50, 51.1], [48, 51.1]], [[51, 35], [51, 28.7], [53, 28.7], [53, 35], [51, 35]], [[52, 22.4], [55, 17.5], [56, 17.5], [53, 22.4], [52, 22.4]], [[58, 12.6], [62, 7], [63, 7], [60, 12.6], [58, 12.6]], [[0, 3.5], [0, 93.1], [64, 93.1], [64, 0], [63, 0], [63, 92.4], [1, 92.4], [1, 3.5], [0, 3.5]]];
for (var i = 0; i < points.length; i++) {
for (var k = 0; k < points[i].length; k++) {
points[i][k][0] /= 10.5;
points[i][k][1] /= -10.5 / 0.75;
points[i][k][0] += geoCoord[0];
points[i][k][1] += geoCoord[1];
}
}
export default function fixNanhai(mapType, regions) {
if (mapType === 'china') {
for (var i = 0; i < regions.length; i++) {
// Already exists.
if (regions[i].name === nanhaiName) {
return;
}
}
regions.push(new GeoJSONRegion(nanhaiName, zrUtil.map(points, function (exterior) {
return {
type: 'polygon',
exterior: exterior
};
}), geoCoord));
}
}
+63
View File
@@ -0,0 +1,63 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 coordsOffsetMap = {
'南海诸岛': [32, 80],
// 全国
'广东': [0, -10],
'香港': [10, 5],
'澳门': [-10, 10],
// '北京': [-10, 0],
'天津': [5, 5]
};
export default function fixTextCoords(mapType, region) {
if (mapType === 'china') {
var coordFix = coordsOffsetMap[region.name];
if (coordFix) {
var cp = region.getCenter();
cp[0] += coordFix[0] / 10.5;
cp[1] += -coordFix[1] / (10.5 / 0.75);
region.setCenter(cp);
}
}
}
+256
View File
@@ -0,0 +1,256 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import Geo, { geo2DDimensions } from './Geo.js';
import * as layout from '../../util/layout.js';
import * as numberUtil from '../../util/number.js';
import geoSourceManager from './geoSourceManager.js';
import { buildAllMapSeriesGroups, mapSeriesGroupHasOwnGeo, SERIES_TYPE_MAP } from '../../chart/map/MapSeries.js';
import * as vector from 'zrender/lib/core/vector.js';
import { injectCoordSysByOption } from '../../core/CoordinateSystem.js';
import { SINGLE_REFERRING } from '../../util/model.js';
import { viewCoordSysSetBoundingRect, viewCoordSysSetRoamOptionFromModel, viewCoordSysSetViewRect } from '../View.js';
/**
* Resize method bound to the geo
*/
function resizeGeo(geoModel, api) {
var viewCoordSys = this.view;
var boundingCoords = geoModel.get('boundingCoords');
if (boundingCoords != null) {
var leftTop_1 = boundingCoords[0];
var rightBottom_1 = boundingCoords[1];
if (!(isFinite(leftTop_1[0]) && isFinite(leftTop_1[1]) && isFinite(rightBottom_1[0]) && isFinite(rightBottom_1[1]))) {
if (process.env.NODE_ENV !== 'production') {
console.error('Invalid boundingCoords');
}
} else {
// Sample around the lng/lat rect and use projection to calculate actual bounding rect.
var projection_1 = this.projection;
if (projection_1) {
var xMin = leftTop_1[0];
var yMin = leftTop_1[1];
var xMax = rightBottom_1[0];
var yMax = rightBottom_1[1];
leftTop_1 = [Infinity, Infinity];
rightBottom_1 = [-Infinity, -Infinity];
// TODO better way?
var sampleLine = function (x0, y0, x1, y1) {
var dx = x1 - x0;
var dy = y1 - y0;
for (var i = 0; i <= 100; i++) {
var p = i / 100;
var pt = projection_1.project([x0 + dx * p, y0 + dy * p]);
vector.min(leftTop_1, leftTop_1, pt);
vector.max(rightBottom_1, rightBottom_1, pt);
}
};
// Top
sampleLine(xMin, yMin, xMax, yMin);
// Right
sampleLine(xMax, yMin, xMax, yMax);
// Bottom
sampleLine(xMax, yMax, xMin, yMax);
// Left
sampleLine(xMin, yMax, xMax, yMin);
}
viewCoordSysSetBoundingRect(viewCoordSys, leftTop_1[0], leftTop_1[1], rightBottom_1[0] - leftTop_1[0], rightBottom_1[1] - leftTop_1[1]);
}
}
var rect = viewCoordSys.getBoundingRect();
var centerOption = geoModel.get('layoutCenter');
var sizeOption = geoModel.get('layoutSize');
// Laying out geo on Cartesian works theoretically but not supported yet.
// Currently, we only support to lay out on matrix/calendar.
var refContainer = layout.createBoxLayoutReference(geoModel, api).refContainer;
var aspect = rect.width / rect.height * this.aspectScale;
var useCenterAndSize = false;
var center;
var size;
if (centerOption && sizeOption) {
center = [numberUtil.parsePercent(centerOption[0], refContainer.width) + refContainer.x, numberUtil.parsePercent(centerOption[1], refContainer.height) + refContainer.y];
size = numberUtil.parsePercent(sizeOption, Math.min(refContainer.width, refContainer.height));
if (!isNaN(center[0]) && !isNaN(center[1]) && !isNaN(size)) {
useCenterAndSize = true;
} else {
if (process.env.NODE_ENV !== 'production') {
console.warn('Given layoutCenter or layoutSize data are invalid. Use left/top/width/height instead.');
}
}
}
var viewRect;
if (useCenterAndSize) {
viewRect = {};
if (aspect > 1) {
// Width is same with size
viewRect.width = size;
viewRect.height = size / aspect;
} else {
viewRect.height = size;
viewRect.width = size * aspect;
}
viewRect.y = center[1] - viewRect.height / 2;
viewRect.x = center[0] - viewRect.width / 2;
} else {
// Use left/top/width/height
var boxLayoutOption = geoModel.getBoxLayoutParams();
boxLayoutOption.aspect = aspect;
viewRect = layout.getLayoutRect(boxLayoutOption, refContainer);
viewRect = layout.applyPreserveAspect(geoModel, viewRect, aspect);
}
viewCoordSysSetViewRect(viewCoordSys, viewRect.x, viewRect.y, viewRect.width, viewRect.height);
viewCoordSysSetRoamOptionFromModel(viewCoordSys, geoModel);
}
// Back compat for ECharts2, where the coord map is set on map series:
// {type: 'map', geoCoord: {'cityA': [116.46,39.92], 'cityA': [119.12,24.61]}},
function setGeoCoords(geo, model) {
zrUtil.each(model.get('geoCoord'), function (geoCoord, name) {
geo.addGeoCoord(name, geoCoord);
});
}
var GeoCreator = /** @class */function () {
function GeoCreator() {
// For deciding which dimensions to use when creating list data
this.dimensions = geo2DDimensions;
}
GeoCreator.prototype.create = function (ecModel, api) {
var geoList = [];
function getCommonGeoProperties(model) {
return {
nameProperty: model.get('nameProperty'),
aspectScale: model.get('aspectScale'),
projection: model.get('projection'),
clip: model.getShallow('clip', true)
};
}
// FIXME Create each time may be slow
ecModel.eachComponent('geo', function (geoModel, idx) {
var mapName = geoModel.get('map');
var geo = new Geo(mapName + idx, mapName, zrUtil.extend({
nameMap: geoModel.get('nameMap'),
api: api,
ecModel: ecModel
}, getCommonGeoProperties(geoModel)));
geoList.push(geo);
// setGeoCoords(geo, geoModel);
geoModel.coordinateSystem = geo;
geo.model = geoModel;
// Inject resize method
geo.resize = resizeGeo;
geo.resize(geoModel, api);
});
ecModel.eachSeries(function (seriesModel) {
injectCoordSysByOption({
targetModel: seriesModel,
coordSysType: 'geo',
coordSysProvider: function () {
var geoModel = seriesModel.subType === SERIES_TYPE_MAP ? seriesModel.getHostGeoModel() : seriesModel.getReferringComponents('geo', SINGLE_REFERRING).models[0];
return geoModel && geoModel.coordinateSystem;
},
allowNotFound: true
});
});
// If has map series
zrUtil.each(buildAllMapSeriesGroups(ecModel, true), function (mapSeriesGroup, groupKey) {
if (!mapSeriesGroupHasOwnGeo(groupKey)) {
return;
}
var firstDeclaredMapSeries = mapSeriesGroup.r[0];
var nameMapList = [];
zrUtil.each(mapSeriesGroup.r, function (mapSeries) {
nameMapList.push(mapSeries.get('nameMap'));
// MAP_SERIES_GROUP must not be set here, as series filtering is not performed.
// Clear it first, including series to be filtered.
mapSeries.seriesGroup = null;
});
var mapType = groupKey.slice(1);
var geo = new Geo(mapType, mapType, zrUtil.extend({
nameMap: zrUtil.mergeAll(nameMapList),
api: api,
ecModel: ecModel
}, getCommonGeoProperties(firstDeclaredMapSeries)));
var scaleLimit;
zrUtil.each(mapSeriesGroup.r, function (mapSeries) {
scaleLimit = zrUtil.retrieve2(scaleLimit, mapSeries.get('scaleLimit'));
});
geoList.push(geo);
// Inject resize method
geo.resize = resizeGeo;
geo.resize(firstDeclaredMapSeries, api);
zrUtil.each(mapSeriesGroup.r, function (mapSeries) {
mapSeries.coordinateSystem = geo;
setGeoCoords(geo, mapSeries);
});
});
return geoList;
};
/**
* Fill given regions array
*/
GeoCreator.prototype.getFilledRegions = function (originRegionArr, mapName, nameMap, nameProperty) {
// Not use the original
var regionsArr = (originRegionArr || []).slice();
var dataNameMap = zrUtil.createHashMap();
for (var i = 0; i < regionsArr.length; i++) {
dataNameMap.set(regionsArr[i].name, regionsArr[i]);
}
var source = geoSourceManager.load(mapName, nameMap, nameProperty);
zrUtil.each(source.regions, function (region) {
var name = region.name;
var regionOption = dataNameMap.get(name);
// apply specified echarts style in GeoJSON data
var specifiedGeoJSONRegionStyle = region.properties && region.properties.echartsStyle;
if (!regionOption) {
regionOption = {
name: name
};
regionsArr.push(regionOption);
}
specifiedGeoJSONRegionStyle && zrUtil.merge(regionOption, specifiedGeoJSONRegionStyle);
});
return regionsArr;
};
return GeoCreator;
}();
var geoCreator = new GeoCreator();
export default geoCreator;
+121
View File
@@ -0,0 +1,121 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { createHashMap } from 'zrender/lib/core/util.js';
import { GeoSVGResource } from './GeoSVGResource.js';
import { GeoJSONResource } from './GeoJSONResource.js';
var storage = createHashMap();
export default {
/**
* Compatible with previous `echarts.registerMap`.
*
* @usage
* ```js
*
* echarts.registerMap('USA', geoJson, specialAreas);
*
* echarts.registerMap('USA', {
* geoJson: geoJson,
* specialAreas: {...}
* });
* echarts.registerMap('USA', {
* geoJSON: geoJson,
* specialAreas: {...}
* });
*
* echarts.registerMap('airport', {
* svg: svg
* }
* ```
*
* Note:
* Do not support that register multiple geoJSON or SVG
* one map name. Because different geoJSON and SVG have
* different unit. It's not easy to make sure how those
* units are mapping/normalize.
* If intending to use multiple geoJSON or SVG, we can
* use multiple geo coordinate system.
*/
registerMap: function (mapName, rawDef, rawSpecialAreas) {
if (rawDef.svg) {
var resource = new GeoSVGResource(mapName, rawDef.svg);
storage.set(mapName, resource);
} else {
// Recommend:
// echarts.registerMap('eu', { geoJSON: xxx, specialAreas: xxx });
// Backward compatibility:
// echarts.registerMap('eu', geoJSON, specialAreas);
// echarts.registerMap('eu', { geoJson: xxx, specialAreas: xxx });
var geoJSON = rawDef.geoJson || rawDef.geoJSON;
if (geoJSON && !rawDef.features) {
rawSpecialAreas = rawDef.specialAreas;
} else {
geoJSON = rawDef;
}
var resource = new GeoJSONResource(mapName, geoJSON, rawSpecialAreas);
storage.set(mapName, resource);
}
},
getGeoResource: function (mapName) {
return storage.get(mapName);
},
/**
* Only for exporting to users.
* **MUST NOT** used internally.
*/
getMapForUser: function (mapName) {
var resource = storage.get(mapName);
// Do not support return SVG until some real requirement come.
return resource && resource.type === 'geoJSON' && resource.getMapForUser();
},
load: function (mapName, nameMap, nameProperty) {
var resource = storage.get(mapName);
if (!resource) {
if (process.env.NODE_ENV !== 'production') {
console.error('Map ' + mapName + ' not exists. The GeoJSON of the map must be provided.');
}
return;
}
return resource.load(nameMap, nameProperty);
}
};
+54
View File
@@ -0,0 +1,54 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
;
;
;
;
;
;
;
;
;
;
export {};
+146
View File
@@ -0,0 +1,146 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
/**
* Parse and decode geo json
*/
import * as zrUtil from 'zrender/lib/core/util.js';
import { GeoJSONLineStringGeometry, GeoJSONPolygonGeometry, GeoJSONRegion } from './Region.js';
function decode(json) {
if (!json.UTF8Encoding) {
return json;
}
var jsonCompressed = json;
var encodeScale = jsonCompressed.UTF8Scale;
if (encodeScale == null) {
encodeScale = 1024;
}
var features = jsonCompressed.features;
zrUtil.each(features, function (feature) {
var geometry = feature.geometry;
var encodeOffsets = geometry.encodeOffsets;
var coordinates = geometry.coordinates;
// Geometry may be appeded manually in the script after json loaded.
// In this case this geometry is usually not encoded.
if (!encodeOffsets) {
return;
}
switch (geometry.type) {
case 'LineString':
geometry.coordinates = decodeRing(coordinates, encodeOffsets, encodeScale);
break;
case 'Polygon':
decodeRings(coordinates, encodeOffsets, encodeScale);
break;
case 'MultiLineString':
decodeRings(coordinates, encodeOffsets, encodeScale);
break;
case 'MultiPolygon':
zrUtil.each(coordinates, function (rings, idx) {
return decodeRings(rings, encodeOffsets[idx], encodeScale);
});
}
});
// Has been decoded
jsonCompressed.UTF8Encoding = false;
return jsonCompressed;
}
function decodeRings(rings, encodeOffsets, encodeScale) {
for (var c = 0; c < rings.length; c++) {
rings[c] = decodeRing(rings[c], encodeOffsets[c], encodeScale);
}
}
function decodeRing(coordinate, encodeOffsets, encodeScale) {
var result = [];
var prevX = encodeOffsets[0];
var prevY = encodeOffsets[1];
for (var i = 0; i < coordinate.length; i += 2) {
var x = coordinate.charCodeAt(i) - 64;
var y = coordinate.charCodeAt(i + 1) - 64;
// ZigZag decoding
x = x >> 1 ^ -(x & 1);
y = y >> 1 ^ -(y & 1);
// Delta deocding
x += prevX;
y += prevY;
prevX = x;
prevY = y;
// Dequantize
result.push([x / encodeScale, y / encodeScale]);
}
return result;
}
export default function parseGeoJSON(geoJson, nameProperty) {
geoJson = decode(geoJson);
return zrUtil.map(zrUtil.filter(geoJson.features, function (featureObj) {
// Output of mapshaper may have geometry null
return featureObj.geometry && featureObj.properties && featureObj.geometry.coordinates.length > 0;
}), function (featureObj) {
var properties = featureObj.properties;
var geo = featureObj.geometry;
var geometries = [];
switch (geo.type) {
case 'Polygon':
var coordinates = geo.coordinates;
// According to the GeoJSON specification.
// First must be exterior, and the rest are all interior(holes).
geometries.push(new GeoJSONPolygonGeometry(coordinates[0], coordinates.slice(1)));
break;
case 'MultiPolygon':
zrUtil.each(geo.coordinates, function (item) {
if (item[0]) {
geometries.push(new GeoJSONPolygonGeometry(item[0], item.slice(1)));
}
});
break;
case 'LineString':
geometries.push(new GeoJSONLineStringGeometry([geo.coordinates]));
break;
case 'MultiLineString':
geometries.push(new GeoJSONLineStringGeometry(geo.coordinates));
}
var region = new GeoJSONRegion(properties[nameProperty || 'name'], geometries, properties.cp);
region.properties = properties;
return region;
});
}
+81
View File
@@ -0,0 +1,81 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import { viewCoordSysGetZoomOption } from '../View.js';
function dataToCoordSize(dataSize, dataItem) {
dataItem = dataItem || [0, 0];
return zrUtil.map([0, 1], function (dimIdx) {
var val = dataItem[dimIdx];
var halfSize = dataSize[dimIdx] / 2;
var p1 = [];
var p2 = [];
p1[dimIdx] = val - halfSize;
p2[dimIdx] = val + halfSize;
p1[1 - dimIdx] = p2[1 - dimIdx] = dataItem[1 - dimIdx];
return Math.abs(this.dataToPoint(p1)[dimIdx] - this.dataToPoint(p2)[dimIdx]);
}, this);
}
export default function geoPrepareCustom(coordSys) {
var viewCoordSys = coordSys.view;
var rect = viewCoordSys.getBoundingRect();
return {
coordSys: {
type: 'geo',
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
zoom: viewCoordSysGetZoomOption(viewCoordSys)
},
api: {
coord: function (data) {
// do not provide "out" and noRoam param,
// Compatible with this usage:
// echarts.util.map(item.points, api.coord)
return coordSys.dataToPoint(data);
},
size: zrUtil.bind(dataToCoordSize, coordSys)
}
};
}
+466
View File
@@ -0,0 +1,466 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { getLayoutRect } from '../../util/layout.js';
import { ListIterator } from '../../util/model.js';
import { eqNaN, isArray, retrieve2 } from 'zrender/lib/core/util.js';
import { WH, XY } from '../../util/graphic.js';
import Model from '../../model/Model.js';
import { mathMax, mathMin, parsePositionSizeOption } from '../../util/number.js';
import { createNaNRectLike, MatrixClampOption, MatrixCellLayoutInfoType, parseCoordRangeOption, resetXYLocatorRange, xyLocatorRangeToRectOneDim } from './matrixCoordHelper.js';
import { error } from '../../util/log.js';
import { injectCoordSysByOption, simpleCoordSysInjectionProvider } from '../../core/CoordinateSystem.js';
var Matrix = /** @class */function () {
function Matrix(matrixModel, ecModel, api) {
this.dimensions = Matrix.dimensions;
this.type = 'matrix';
this._model = matrixModel;
var models = this._dimModels = {
x: matrixModel.getDimensionModel('x'),
y: matrixModel.getDimensionModel('y')
};
this._dims = {
x: models.x.dim,
y: models.y.dim
};
this._resize(matrixModel, api);
}
/**
* @see fetchers in `model/referHelper.ts`,
* which is used to parse data in ordinal way.
* In most series only 'x' and 'y' is required,
* but some series, such as heatmap, can specify value.
*/
Matrix.getDimensionsInfo = function () {
return [{
name: 'x',
type: 'ordinal'
}, {
name: 'y',
type: 'ordinal'
}, {
name: 'value'
}];
};
Matrix.create = function (ecModel, api) {
var matrixList = [];
ecModel.eachComponent('matrix', function (matrixModel) {
var matrix = new Matrix(matrixModel, ecModel, api);
matrixList.push(matrix);
matrixModel.coordinateSystem = matrix;
});
// Inject coordinate system
// PENDING: optimize to not to travel all components?
// (collect relevant components in ecModel only when model update?)
ecModel.eachComponent(function (mainType, componentModel) {
injectCoordSysByOption({
targetModel: componentModel,
coordSysType: 'matrix',
coordSysProvider: simpleCoordSysInjectionProvider
});
});
return matrixList;
};
Matrix.prototype.getRect = function () {
return this._rect;
};
Matrix.prototype._resize = function (matrixModel, api) {
var dims = this._dims;
var dimModels = this._dimModels;
var rect = this._rect = getLayoutRect(matrixModel.getBoxLayoutParams(), {
width: api.getWidth(),
height: api.getHeight()
});
layOutUnitsOnDimension(dimModels, dims, rect, 0);
layOutUnitsOnDimension(dimModels, dims, rect, 1);
layOutDimCellsRestInfoByUnit(0, dims);
layOutDimCellsRestInfoByUnit(1, dims);
layOutBodyCornerCellMerge(this._model.getBody(), dims);
layOutBodyCornerCellMerge(this._model.getCorner(), dims);
};
/**
* @implement
* - The input is allowed to be `[NaN/null/undefined, xxx]`/`[xxx, NaN/null/undefined]`;
* the return is `[NaN, xxxresult]`/`[xxxresult, NaN]` or clamped boundary value if
* `clamp` passed. This is for the usage that only get coord on single x or y.
* - Alwasy return an numeric array, but never be null/undefined.
* If it can not be located or invalid, return `[NaN, NaN]`.
*/
Matrix.prototype.dataToPoint = function (data, opt, out) {
out = out || [];
this.dataToLayout(data, opt, _dtpOutDataToLayout);
out[0] = _dtpOutDataToLayout.rect.x + _dtpOutDataToLayout.rect.width / 2;
out[1] = _dtpOutDataToLayout.rect.y + _dtpOutDataToLayout.rect.height / 2;
return out;
};
/**
* @implement
* - The input is allowed to be `[NaN/null/undefined, xxx]`/`[xxx, NaN/null/undefined]`;
* the return is `{x: NaN, width: NaN, y: xxxresulty, height: xxxresulth}`/
* `{y: NaN, height: NaN, x: xxxresultx, width: xxxresultw}` or clamped boundary value
* if `clamp` passed. This is for the usage that only get coord on single x or y.
* - The returned `out.rect` and `out.matrixXYLocatorRange` is always an object or an 2d-array,
* but never be null/undefined. If it cannot be located or invalid, `NaN` is in their
* corresponding number props.
* - Do not provide `out.contentRect`, because it's allowed to input non-leaf dimension x/y or
* a range of x/y, which determines a rect covering multiple cells (even not merged), in which
* case the padding and borderWidth can not be determined to make a contentRect. Therefore only
* return `out.rect` in any case for consistency. The caller is responsible for adding space to
* avoid covering cell borders, if necessary.
*/
Matrix.prototype.dataToLayout = function (data, opt, out) {
var dims = this._dims;
out = out || {};
var outRect = out.rect = out.rect || {};
outRect.x = outRect.y = outRect.width = outRect.height = NaN;
var outLocRange = out.matrixXYLocatorRange = resetXYLocatorRange(out.matrixXYLocatorRange);
if (!isArray(data)) {
if (process.env.NODE_ENV !== 'production') {
error('Input data must be an array in `convertToLayout`, `convertToPixel`');
}
return out;
}
parseCoordRangeOption(outLocRange, null, data, dims, retrieve2(opt && opt.clamp, MatrixClampOption.none));
if (!opt || !opt.ignoreMergeCells) {
if (!opt || opt.clamp !== MatrixClampOption.corner) {
this._model.getBody().expandRangeByCellMerge(outLocRange);
}
if (!opt || opt.clamp !== MatrixClampOption.body) {
this._model.getCorner().expandRangeByCellMerge(outLocRange);
}
}
xyLocatorRangeToRectOneDim(outRect, outLocRange, dims, 0);
xyLocatorRangeToRectOneDim(outRect, outLocRange, dims, 1);
return out;
};
/**
* The returned locator pair can be the input of `dataToPoint` or `dataToLayout`.
*
* If point[0] is out of the matrix rect,
* the out[0] is NaN;
* else if it is on the right of top-left corner of body,
* the out[0] is the oridinal number (>= 0).
* else
* out[0] is the locator for corner or header (<= 0).
*
* The same rule goes for point[1] and out[1].
*
* But point[0] and point[1] are calculated separately, i.e.,
* the reuslt can be `[1, NaN]` or `[NaN, 1]` if only one dimension is out of boundary.
*
* @implement
*/
Matrix.prototype.pointToData = function (point, opt, out) {
var dims = this._dims;
pointToDataOneDimPrepareCtx(_tmpCtxPointToData, 0, dims, point, opt && opt.clamp);
pointToDataOneDimPrepareCtx(_tmpCtxPointToData, 1, dims, point, opt && opt.clamp);
out = out || [];
out[0] = out[1] = NaN;
if (_tmpCtxPointToData.y === CtxPointToDataAreaType.inCorner && _tmpCtxPointToData.x === CtxPointToDataAreaType.inBody) {
pointToDataOnlyHeaderFillOut(_tmpCtxPointToData, out, 0, dims);
} else if (_tmpCtxPointToData.x === CtxPointToDataAreaType.inCorner && _tmpCtxPointToData.y === CtxPointToDataAreaType.inBody) {
pointToDataOnlyHeaderFillOut(_tmpCtxPointToData, out, 1, dims);
} else {
pointToDataBodyCornerFillOut(_tmpCtxPointToData, out, 0, dims);
pointToDataBodyCornerFillOut(_tmpCtxPointToData, out, 1, dims);
}
return out;
};
Matrix.prototype.convertToPixel = function (ecModel, finder, value, opt) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.dataToPoint(value, opt) : undefined;
};
Matrix.prototype.convertToLayout = function (ecModel, finder, value, opt) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.dataToLayout(value, opt) : undefined;
};
Matrix.prototype.convertFromPixel = function (ecModel, finder, pixel, opt) {
var coordSys = getCoordSys(finder);
return coordSys === this ? coordSys.pointToData(pixel, opt) : undefined;
};
Matrix.prototype.containPoint = function (point) {
return this._rect.contain(point[0], point[1]);
};
Matrix.dimensions = ['x', 'y', 'value'];
return Matrix;
}();
var _dtpOutDataToLayout = {
rect: createNaNRectLike()
};
var _ptdLevelIt = new ListIterator();
var _ptdDimCellIt = new ListIterator();
function layOutUnitsOnDimension(dimModels, dims, matrixRect, dimIdx) {
var otherDimIdx = 1 - dimIdx;
var thisDim = dims[XY[dimIdx]];
var otherDim = dims[XY[otherDimIdx]];
// Notice: If matrix.x/y.show is false, still lay out, to ensure the
// consistent return of `dataToLayout`.
var otherDimShow = otherDim.shouldShow();
// Reset
for (var it_1 = thisDim.resetCellIterator(); it_1.next();) {
it_1.item.wh = it_1.item.xy = NaN;
}
for (var it_2 = otherDim.resetLayoutIterator(null, dimIdx); it_2.next();) {
it_2.item.wh = it_2.item.xy = NaN;
}
// Set specified size from option.
var restSize = matrixRect[WH[dimIdx]];
var restCellsCount = thisDim.getLocatorCount(dimIdx) + otherDim.getLocatorCount(dimIdx);
var tmpLevelModel = new Model();
for (var it_3 = otherDim.resetLevelIterator(); it_3.next();) {
// Consider `matrix.x.levelSize` and `matrix.x.levels[i].levelSize`.
tmpLevelModel.option = it_3.item.option;
tmpLevelModel.parentModel = dimModels[XY[otherDimIdx]];
layOutSpecified(it_3.item, otherDimShow ? tmpLevelModel.get('levelSize') : 0);
}
var tmpCellModel = new Model();
for (var it_4 = thisDim.resetCellIterator(); it_4.next();) {
// Only leaf support size specification, to avoid unnecessary complexity.
if (it_4.item.type === MatrixCellLayoutInfoType.leaf) {
tmpCellModel.option = it_4.item.option;
tmpCellModel.parentModel = undefined;
layOutSpecified(it_4.item, tmpCellModel.get('size'));
}
}
function layOutSpecified(item, sizeOption) {
var size = parseSizeOption(sizeOption, dimIdx, matrixRect);
if (!eqNaN(size)) {
item.wh = confineSize(size, restSize);
restSize = confineSize(restSize - item.wh);
restCellsCount--;
}
}
// Set all sizes and positions to levels and leaf cells of which size is unspecified.
// Contents lay out based on matrix, rather than inverse; therefore do not support
// calculating size based on content, but allocate equally.
var computedCellWH = restCellsCount ? restSize / restCellsCount : 0;
// If all size specified, but some space remain (may also caused by matrix.x/y.show: false)
// do not align to the big most edge.
var notAlignToBigmost = !restCellsCount && restSize >= 1; // `1` for cumulative precision error.
var currXY = matrixRect[XY[dimIdx]];
var maxLocator = thisDim.getLocatorCount(dimIdx) - 1;
var it = new ListIterator();
// Lay out levels of the perpendicular dim.
for (otherDim.resetLayoutIterator(it, dimIdx); it.next();) {
layOutUnspecified(it.item);
}
for (thisDim.resetLayoutIterator(it, dimIdx); it.next();) {
layOutUnspecified(it.item);
}
function layOutUnspecified(item) {
if (eqNaN(item.wh)) {
item.wh = computedCellWH;
}
item.xy = currXY;
if (item.id[XY[dimIdx]] === maxLocator && !notAlignToBigmost) {
// Align to the rightmost border, consider cumulative precision error.
item.wh = matrixRect[XY[dimIdx]] + matrixRect[WH[dimIdx]] - item.xy;
}
currXY += item.wh;
}
}
function layOutDimCellsRestInfoByUnit(dimIdx, dims) {
// Finally save layout info based on the unit leaves and levels.
for (var it_5 = dims[XY[dimIdx]].resetCellIterator(); it_5.next();) {
var dimCell = it_5.item;
layOutRectOneDimBasedOnUnit(dimCell.rect, dimIdx, dimCell.id, dimCell.span, dims);
// Consider level varitation on tree leaves, should extend the size to touch matrix body
// to avoid weird appearance.
layOutRectOneDimBasedOnUnit(dimCell.rect, 1 - dimIdx, dimCell.id, dimCell.span, dims);
if (dimCell.type === MatrixCellLayoutInfoType.nonLeaf) {
// `xy` and `wh` need to be saved in non-leaf since it supports locating by non-leaf
// in `dataToPoint` or `dataToLayout`.
dimCell.xy = dimCell.rect[XY[dimIdx]];
dimCell.wh = dimCell.rect[WH[dimIdx]];
}
}
}
function layOutBodyCornerCellMerge(bodyOrCorner, dims) {
bodyOrCorner.travelExistingCells(function (cell) {
var computedSpan = cell.span;
if (computedSpan) {
var layoutRect = cell.spanRect;
var id = cell.id;
layOutRectOneDimBasedOnUnit(layoutRect, 0, id, computedSpan, dims);
layOutRectOneDimBasedOnUnit(layoutRect, 1, id, computedSpan, dims);
}
});
}
// Save to rect for rendering.
function layOutRectOneDimBasedOnUnit(outRect, dimIdx, id, span, dims) {
outRect[WH[dimIdx]] = 0;
var locator = id[XY[dimIdx]];
var dim = locator < 0 ? dims[XY[1 - dimIdx]] : dims[XY[dimIdx]];
var layoutUnit = dim.getUnitLayoutInfo(dimIdx, id[XY[dimIdx]]);
outRect[XY[dimIdx]] = layoutUnit.xy;
outRect[WH[dimIdx]] = layoutUnit.wh;
if (span[XY[dimIdx]] > 1) {
var layoutUnit2 = dim.getUnitLayoutInfo(dimIdx, id[XY[dimIdx]] + span[XY[dimIdx]] - 1);
// Be careful the cumulative error - cell must be aligned.
outRect[WH[dimIdx]] = layoutUnit2.xy + layoutUnit2.wh - layoutUnit.xy;
}
}
/**
* Return NaN if not defined or invalid.
*/
function parseSizeOption(sizeOption, dimIdx, matrixRect) {
var sizeNum = parsePositionSizeOption(sizeOption, matrixRect[WH[dimIdx]]);
return confineSize(sizeNum, matrixRect[WH[dimIdx]]);
}
function confineSize(sizeNum, sizeLimit) {
return Math.max(Math.min(sizeNum, retrieve2(sizeLimit, Infinity)), 0);
}
function getCoordSys(finder) {
var matrixModel = finder.matrixModel;
var seriesModel = finder.seriesModel;
var coordSys = matrixModel ? matrixModel.coordinateSystem : seriesModel ? seriesModel.coordinateSystem : null;
return coordSys;
}
var CtxPointToDataAreaType = {
inBody: 1,
inCorner: 2,
outside: 3
};
// For quick performance optimization in pointToData.
var _tmpCtxPointToData = {
x: null,
y: null,
point: []
};
function pointToDataOneDimPrepareCtx(ctx, dimIdx, dims, point, clamp) {
var thisDim = dims[XY[dimIdx]];
var otherDim = dims[XY[1 - dimIdx]];
// Notice: considered cases: `matrix.x/y.show: false`, `matrix.x/y.data` is empty.
// In this cases the `layout.xy` is on the edge and `layout.wh` is `0`; they still can be
// use to calculate clampping.
var bodyMaxUnit = thisDim.getUnitLayoutInfo(dimIdx, thisDim.getLocatorCount(dimIdx) - 1);
var body0Unit = thisDim.getUnitLayoutInfo(dimIdx, 0);
var cornerMinUnit = otherDim.getUnitLayoutInfo(dimIdx, -otherDim.getLocatorCount(dimIdx));
var cornerMinus1Unit = otherDim.shouldShow() ? otherDim.getUnitLayoutInfo(dimIdx, -1) : null;
var coord = ctx.point[dimIdx] = point[dimIdx]; // Transfer the oridinal coord.
if (!body0Unit && !cornerMinus1Unit) {
ctx[XY[dimIdx]] = CtxPointToDataAreaType.outside;
return;
}
if (clamp === MatrixClampOption.body) {
if (body0Unit) {
ctx[XY[dimIdx]] = CtxPointToDataAreaType.inBody;
coord = mathMin(bodyMaxUnit.xy + bodyMaxUnit.wh, mathMax(body0Unit.xy, coord));
ctx.point[dimIdx] = coord;
} else {
// If clamp to body, the result must not be in header.
ctx[XY[dimIdx]] = CtxPointToDataAreaType.outside;
}
return;
} else if (clamp === MatrixClampOption.corner) {
if (cornerMinus1Unit) {
ctx[XY[dimIdx]] = CtxPointToDataAreaType.inCorner;
coord = mathMin(cornerMinus1Unit.xy + cornerMinus1Unit.wh, mathMax(cornerMinUnit.xy, coord));
ctx.point[dimIdx] = coord;
} else {
// If clamp to corner, the result must not be in body.
ctx[XY[dimIdx]] = CtxPointToDataAreaType.outside;
}
return;
}
var pxLoc0 = body0Unit ? body0Unit.xy : cornerMinus1Unit ? cornerMinus1Unit.xy + cornerMinus1Unit.wh : NaN;
var pxMin = cornerMinUnit ? cornerMinUnit.xy : pxLoc0;
var pxMax = bodyMaxUnit ? bodyMaxUnit.xy + bodyMaxUnit.wh : pxLoc0;
if (coord < pxMin) {
if (!clamp) {
// Quick pass for later calc, since mouse event on any place will enter this method if use `pointToData`.
ctx[XY[dimIdx]] = CtxPointToDataAreaType.outside;
return;
}
coord = pxMin;
} else if (coord > pxMax) {
if (!clamp) {
ctx[XY[dimIdx]] = CtxPointToDataAreaType.outside;
return;
}
coord = pxMax;
}
ctx.point[dimIdx] = coord; // Save the updated coord.
ctx[XY[dimIdx]] = pxLoc0 <= coord && coord <= pxMax ? CtxPointToDataAreaType.inBody : pxMin <= coord && coord <= pxLoc0 ? CtxPointToDataAreaType.inCorner : CtxPointToDataAreaType.outside;
// Every props in ctx must be set in every branch of this method.
}
// Assume partialOut has been set to NaN outside.
// This method may fill out[0] and out[1] in one call.
function pointToDataOnlyHeaderFillOut(ctx, partialOut, dimIdx, dims) {
var otherDimIdx = 1 - dimIdx;
if (ctx[XY[dimIdx]] === CtxPointToDataAreaType.outside) {
return;
}
for (dims[XY[dimIdx]].resetCellIterator(_ptdDimCellIt); _ptdDimCellIt.next();) {
var cell = _ptdDimCellIt.item;
if (isCoordInRect(ctx.point[dimIdx], cell.rect, dimIdx) && isCoordInRect(ctx.point[otherDimIdx], cell.rect, otherDimIdx)) {
// non-leaves are also allowed to be located.
// If the point is in x or y dimension cell area, should check both x and y coord to
// determine a cell; in this way a non-leaf cell can be determined.
partialOut[dimIdx] = cell.ordinal;
partialOut[otherDimIdx] = cell.id[XY[otherDimIdx]];
return;
}
}
}
// Assume partialOut has been set to NaN outside.
// This method may fill out[0] and out[1] in one call.
function pointToDataBodyCornerFillOut(ctx, partialOut, dimIdx, dims) {
if (ctx[XY[dimIdx]] === CtxPointToDataAreaType.outside) {
return;
}
var dim = ctx[XY[dimIdx]] === CtxPointToDataAreaType.inCorner ? dims[XY[1 - dimIdx]] : dims[XY[dimIdx]];
for (dim.resetLayoutIterator(_ptdLevelIt, dimIdx); _ptdLevelIt.next();) {
if (isCoordInLayoutInfo(ctx.point[dimIdx], _ptdLevelIt.item)) {
partialOut[dimIdx] = _ptdLevelIt.item.id[XY[dimIdx]];
return;
}
}
}
function isCoordInLayoutInfo(coord, cell) {
return cell.xy <= coord && coord <= cell.xy + cell.wh;
}
function isCoordInRect(coord, rect, dimIdx) {
return rect[XY[dimIdx]] <= coord && coord <= rect[XY[dimIdx]] + rect[WH[dimIdx]];
}
export default Matrix;
+227
View File
@@ -0,0 +1,227 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { createHashMap, each, extend, isArray, isObject } from 'zrender/lib/core/util.js';
import { error } from '../../util/log.js';
import Point from 'zrender/lib/core/Point.js';
import { resolveXYLocatorRangeByCellMerge, MatrixClampOption, parseCoordRangeOption, fillIdSpanFromLocatorRange, createNaNRectLike, isXYLocatorRangeInvalidOnDim, resetXYLocatorRange, cloneXYLocatorRange } from './matrixCoordHelper.js';
/**
* Lifetime: the same with `MatrixModel`, but different from `coord/Matrix`.
*/
var MatrixBodyCorner = /** @class */function () {
function MatrixBodyCorner(kind, bodyOrCornerModel, dims) {
this._model = bodyOrCornerModel;
this._dims = dims;
this._kind = kind;
this._cellMergeOwnerList = [];
}
/**
* Can not be called before series models initialization finished, since the ordinalMeta may
* use collect the values from `series.data` in series initialization.
*/
MatrixBodyCorner.prototype._ensureCellMap = function () {
var self = this;
var _cellMap = self._cellMap;
if (!_cellMap) {
_cellMap = self._cellMap = createHashMap();
fillCellMap();
}
return _cellMap;
function fillCellMap() {
var parsedList = [];
var cellOptionList = self._model.getShallow('data');
if (cellOptionList && !isArray(cellOptionList)) {
if (process.env.NODE_ENV !== 'production') {
error("matrix." + cellOptionList + ".data must be an array if specified.");
}
cellOptionList = null;
}
each(cellOptionList, function (option, idx) {
if (!isObject(option) || !isArray(option.coord)) {
if (process.env.NODE_ENV !== 'production') {
error("Illegal matrix." + self._kind + ".data[" + idx + "], must be a {coord: [...], ...}");
}
return;
}
var locatorRange = resetXYLocatorRange([]);
var reasonArr = null;
if (process.env.NODE_ENV !== 'production') {
reasonArr = [];
}
parseCoordRangeOption(locatorRange, reasonArr, option.coord, self._dims, option.coordClamp ? MatrixClampOption[self._kind] : MatrixClampOption.none);
if (isXYLocatorRangeInvalidOnDim(locatorRange, 0) || isXYLocatorRangeInvalidOnDim(locatorRange, 1)) {
if (process.env.NODE_ENV !== 'production') {
error("Can not determine cells by option matrix." + self._kind + ".data[" + idx + "]: " + ("" + reasonArr.join(' ')));
}
return;
}
var cellMergeOwner = option && option.mergeCells;
var parsed = {
id: new Point(),
span: new Point(),
locatorRange: locatorRange,
option: option,
cellMergeOwner: cellMergeOwner
};
fillIdSpanFromLocatorRange(parsed, locatorRange);
// The order of the `parsedList` determines the precedence of the styles, if there
// are overlaps between ranges specified in different items. Preserve the original
// order of `matrix.body/corner/data` to make it predictable for users.
parsedList.push(parsed);
});
// Resolve cell merging intersection - union to a larger rect.
var mergedMarkList = [];
for (var parsedIdx = 0; parsedIdx < parsedList.length; parsedIdx++) {
var parsed = parsedList[parsedIdx];
if (!parsed.cellMergeOwner) {
continue;
}
var locatorRange = parsed.locatorRange;
resolveXYLocatorRangeByCellMerge(locatorRange, mergedMarkList, parsedList, parsedIdx);
for (var idx = 0; idx < parsedIdx; idx++) {
if (mergedMarkList[idx]) {
parsedList[idx].cellMergeOwner = false;
}
}
if (locatorRange[0][0] !== parsed.id.x || locatorRange[1][0] !== parsed.id.y) {
// The top-left cell of the unioned locatorRange is not this cell any more.
parsed.cellMergeOwner = false;
// Reconcile: simply use the last style and value option if multiple styles involved
// in a merged area, since there might be no commonly used merge strategy.
var newOption = extend({}, parsed.option);
newOption.coord = null;
var newParsed = {
id: new Point(),
span: new Point(),
locatorRange: locatorRange,
option: newOption,
cellMergeOwner: true
};
fillIdSpanFromLocatorRange(newParsed, locatorRange);
parsedList.push(newParsed);
}
}
// Assign options to cells.
each(parsedList, function (parsed) {
var topLeftCell = ensureBodyOrCornerCell(parsed.id.x, parsed.id.y);
if (parsed.cellMergeOwner) {
topLeftCell.cellMergeOwner = true;
topLeftCell.span = parsed.span;
topLeftCell.locatorRange = parsed.locatorRange;
topLeftCell.spanRect = createNaNRectLike();
self._cellMergeOwnerList.push(topLeftCell);
}
if (!parsed.cellMergeOwner && !parsed.option) {
return;
}
for (var yidx = 0; yidx < parsed.span.y; yidx++) {
for (var xidx = 0; xidx < parsed.span.x; xidx++) {
var cell = ensureBodyOrCornerCell(parsed.id.x + xidx, parsed.id.y + yidx);
// If multiple style options are defined on a cell, the later ones takes precedence.
cell.option = parsed.option;
if (parsed.cellMergeOwner) {
cell.inSpanOf = topLeftCell;
}
}
}
});
} // End of fillCellMap
function ensureBodyOrCornerCell(x, y) {
var key = makeCellMapKey(x, y);
var cell = _cellMap.get(key);
if (!cell) {
cell = _cellMap.set(key, {
id: new Point(x, y),
option: null,
inSpanOf: null,
span: null,
spanRect: null,
locatorRange: null,
cellMergeOwner: false
});
}
return cell;
}
};
/**
* Body cells or corner cell are not commonly defined specifically, especially in a large
* table, thus his is a sparse data structure - bodys or corner cells exist only if there
* are options specified to it (in `matrix.body.data` or `matrix.corner.data`);
* otherwise, return `NullUndefined`.
*/
MatrixBodyCorner.prototype.getCell = function (xy) {
// Assert xy do not contain NaN
return this._ensureCellMap().get(makeCellMapKey(xy[0], xy[1]));
};
/**
* Only cell existing (has specific definition or props) will be travelled.
*/
MatrixBodyCorner.prototype.travelExistingCells = function (cb) {
this._ensureCellMap().each(cb);
};
/**
* @param locatorRange Must be the return of `parseCoordRangeOption`.
*/
MatrixBodyCorner.prototype.expandRangeByCellMerge = function (locatorRange) {
if (!isXYLocatorRangeInvalidOnDim(locatorRange, 0) && !isXYLocatorRangeInvalidOnDim(locatorRange, 1) && locatorRange[0][0] === locatorRange[0][1] && locatorRange[1][0] === locatorRange[1][1]) {
// If it locates to a single cell, use this quick path to avoid travelling.
// It is based on the fact that any cell is not contained by more than one cell merging rect.
_tmpERBCMLocator[0] = locatorRange[0][0];
_tmpERBCMLocator[1] = locatorRange[1][0];
var cell = this.getCell(_tmpERBCMLocator);
var inSpanOf = cell && cell.inSpanOf;
if (inSpanOf) {
cloneXYLocatorRange(locatorRange, inSpanOf.locatorRange);
return;
}
}
var list = this._cellMergeOwnerList;
resolveXYLocatorRangeByCellMerge(locatorRange, null, list, list.length);
};
return MatrixBodyCorner;
}();
export { MatrixBodyCorner };
var _tmpERBCMLocator = [];
function makeCellMapKey(x, y) {
return x + "|" + y;
}
+366
View File
@@ -0,0 +1,366 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { createHashMap, defaults, each, eqNaN, isArray, isObject, isString } from 'zrender/lib/core/util.js';
import Point from 'zrender/lib/core/Point.js';
import OrdinalMeta from '../../data/OrdinalMeta.js';
import Ordinal from '../../scale/Ordinal.js';
import { WH, XY } from '../../util/graphic.js';
import { ListIterator } from '../../util/model.js';
import { createNaNRectLike, setDimXYValue, MatrixCellLayoutInfoType } from './matrixCoordHelper.js';
import { error } from '../../util/log.js';
import { mathMax } from '../../util/number.js';
/**
* Lifetime: the same with `MatrixModel`, but different from `coord/Matrix`.
*/
var MatrixDim = /** @class */function () {
function MatrixDim(dim, dimModel) {
// Under the current definition, every leave corresponds a unit cell,
// and leaves can serve as the locator of cells.
// Therefore make sure:
// - The first `_leavesCount` elements in `_cells` are leaves.
// - `_cells[leaf.id[XY[this.dimIdx]]]` is the leaf itself.
// - Leaves of each subtree are placed together, that is, the leaves of a dimCell are:
// `this._cells.slice(dimCell.firstLeafLocator, dimCell.span[XY[this.dimIdx]])`
this._cells = [];
// Can be visited by `_levels[cell.level]` or `_levels[cell.id[1 - dimIdx] + _levels.length]`.
// Items are never be null/undefined after initialized.
this._levels = [];
this.dim = dim;
this.dimIdx = dim === 'x' ? 0 : 1;
this._model = dimModel;
this._uniqueValueGen = createUniqueValueGenerator(dim);
var dimModelData = dimModel.get('data', true);
var length = dimModel.get('length', true);
if (dimModelData != null && !isArray(dimModelData)) {
if (process.env.NODE_ENV !== 'production') {
error("Illegal echarts option - matrix." + this.dim + ".data must be an array if specified.");
}
dimModelData = [];
}
if (dimModelData) {
this._initByDimModelData(dimModelData);
} else if (length != null) {
dimModelData = Array(length);
for (var i = 0; i < length; i++) {
dimModelData[i] = null;
}
this._initByDimModelData(dimModelData);
} else {
this._initBySeriesData();
}
}
MatrixDim.prototype._initByDimModelData = function (dimModelData) {
var self = this;
var _cells = self._cells;
var _levels = self._levels;
var sameLocatorCellsLists = []; // Save for sorting.
var _cellCount = 0;
self._leavesCount = traverseInitCells(dimModelData, 0, 0);
postInitCells();
return;
function traverseInitCells(dimModelData, firstLeafLocator, level) {
var totalSpan = 0;
if (!dimModelData) {
return totalSpan;
}
each(dimModelData, function (option, optionIdx) {
var invalidOption = false;
var cellOption;
if (isString(option)) {
cellOption = {
value: option
};
} else if (isObject(option)) {
cellOption = option;
if (option.value != null && !isString(option.value)) {
invalidOption = true;
cellOption = {
value: null
};
}
} else {
cellOption = {
value: null
};
if (option != null) {
invalidOption = true;
}
}
if (invalidOption) {
if (process.env.NODE_ENV !== 'production') {
error("Illegal echarts option - matrix." + self.dim + ".data[" + optionIdx + "]" + ' must be `string | {value: string}`.');
}
}
var cell = {
type: MatrixCellLayoutInfoType.nonLeaf,
ordinal: NaN,
level: level,
firstLeafLocator: firstLeafLocator,
id: new Point(),
span: setDimXYValue(new Point(), self.dimIdx, 1, 1),
option: cellOption,
xy: NaN,
wh: NaN,
dim: self,
rect: createNaNRectLike()
};
_cellCount++;
(sameLocatorCellsLists[firstLeafLocator] || (sameLocatorCellsLists[firstLeafLocator] = [])).push(cell);
if (!_levels[level]) {
// Create a level only if at least one cell exists.
_levels[level] = {
type: MatrixCellLayoutInfoType.level,
xy: NaN,
wh: NaN,
option: null,
id: new Point(),
dim: self
};
}
var childrenSpan = traverseInitCells(cellOption.children, firstLeafLocator, level + 1);
var subSpan = Math.max(1, childrenSpan);
cell.span[XY[self.dimIdx]] = subSpan;
totalSpan += subSpan;
firstLeafLocator += subSpan;
});
return totalSpan;
}
function postInitCells() {
// Sort to make sure the leaves are at the beginning, so that
// they can be used as the locator of body cells.
var categories = [];
while (_cells.length < _cellCount) {
for (var locator = 0; locator < sameLocatorCellsLists.length; locator++) {
var cell = sameLocatorCellsLists[locator].pop();
if (cell) {
cell.ordinal = categories.length;
var val = cell.option.value;
categories.push(val);
_cells.push(cell);
self._uniqueValueGen.calcDupBase(val);
}
}
}
self._uniqueValueGen.ensureValueUnique(categories, _cells);
var ordinalMeta = self._ordinalMeta = new OrdinalMeta({
categories: categories,
needCollect: false,
deduplication: false
});
self._scale = new Ordinal({
ordinalMeta: ordinalMeta
});
for (var idx = 0; idx < self._leavesCount; idx++) {
var leaf = self._cells[idx];
leaf.type = MatrixCellLayoutInfoType.leaf;
// Handle the tree level variation: enlarge the span of the leaves to reach the body cells.
leaf.span[XY[1 - self.dimIdx]] = self._levels.length - leaf.level;
}
self._initCellsId();
self._initLevelIdOptions();
}
};
MatrixDim.prototype._initBySeriesData = function () {
var self = this;
self._leavesCount = 0;
self._levels = [{
type: MatrixCellLayoutInfoType.level,
xy: NaN,
wh: NaN,
option: null,
id: new Point(),
dim: self
}];
self._initLevelIdOptions();
var ordinalMeta = self._ordinalMeta = new OrdinalMeta({
needCollect: true,
deduplication: true,
onCollect: function (value, ordinalNumber) {
var cell = self._cells[ordinalNumber] = {
type: MatrixCellLayoutInfoType.leaf,
ordinal: ordinalNumber,
level: 0,
firstLeafLocator: ordinalNumber,
id: new Point(),
span: setDimXYValue(new Point(), self.dimIdx, 1, 1),
// Theoretically `value` is from `dataset` or `series.data`, so it may be any type.
// Do not restrict this case for user's convenience, and here simply convert it to
// string for display.
option: {
value: value + ''
},
xy: NaN,
wh: NaN,
dim: self,
rect: createNaNRectLike()
};
self._leavesCount++;
self._setCellId(cell);
}
});
self._scale = new Ordinal({
ordinalMeta: ordinalMeta
});
};
MatrixDim.prototype._setCellId = function (cell) {
var levelsLen = this._levels.length;
var dimIdx = this.dimIdx;
setDimXYValue(cell.id, dimIdx, cell.firstLeafLocator, cell.level - levelsLen);
};
MatrixDim.prototype._initCellsId = function () {
var levelsLen = this._levels.length;
var dimIdx = this.dimIdx;
each(this._cells, function (cell) {
setDimXYValue(cell.id, dimIdx, cell.firstLeafLocator, cell.level - levelsLen);
});
};
MatrixDim.prototype._initLevelIdOptions = function () {
var levelsLen = this._levels.length;
var dimIdx = this.dimIdx;
var levelOptionList = this._model.get('levels', true);
levelOptionList = isArray(levelOptionList) ? levelOptionList : [];
each(this._levels, function (levelCfg, level) {
setDimXYValue(levelCfg.id, dimIdx, 0, level - levelsLen);
levelCfg.option = levelOptionList[level];
});
};
MatrixDim.prototype.shouldShow = function () {
return !!this._model.getShallow('show', true);
};
/**
* Iterate leaves (they are layout units) if dimIdx === this.dimIdx.
* Iterate levels if dimIdx !== this.dimIdx.
*/
MatrixDim.prototype.resetLayoutIterator = function (it, dimIdx, startLocator, count) {
it = it || new ListIterator();
if (dimIdx === this.dimIdx) {
var len = this._leavesCount;
var startIdx = startLocator != null ? Math.max(0, startLocator) : 0;
count = count != null ? Math.min(count, len) : len;
it.reset(this._cells, startIdx, startIdx + count);
} else {
var len = this._levels.length;
// Corner locator is from `-this._levels.length` to `-1`.
var startIdx = startLocator != null ? Math.max(0, startLocator + len) : 0;
count = count != null ? Math.min(count, len) : len;
it.reset(this._levels, startIdx, startIdx + count);
}
return it;
};
MatrixDim.prototype.resetCellIterator = function (it) {
return (it || new ListIterator()).reset(this._cells, 0);
};
MatrixDim.prototype.resetLevelIterator = function (it) {
return (it || new ListIterator()).reset(this._levels, 0);
};
MatrixDim.prototype.getLayout = function (outRect, dimIdx, locator) {
var layout = this.getUnitLayoutInfo(dimIdx, locator);
outRect[XY[dimIdx]] = layout ? layout.xy : NaN;
outRect[WH[dimIdx]] = layout ? layout.wh : NaN;
};
/**
* Get leaf cell or get level info.
* Should be able to return null/undefined if not found on x or y, thus input `dimIdx` is needed.
*/
MatrixDim.prototype.getUnitLayoutInfo = function (dimIdx, locator) {
return dimIdx === this.dimIdx ? locator < this._leavesCount ? this._cells[locator] : undefined : this._levels[locator + this._levels.length];
};
/**
* Get dimension cell by data, including leaves and non-leaves.
*/
MatrixDim.prototype.getCell = function (value) {
var ordinal = this._scale.parse(value);
return eqNaN(ordinal) ? undefined : this._cells[ordinal];
};
/**
* Get leaf count or get level count.
*/
MatrixDim.prototype.getLocatorCount = function (dimIdx) {
return dimIdx === this.dimIdx ? this._leavesCount : this._levels.length;
};
MatrixDim.prototype.getOrdinalMeta = function () {
return this._ordinalMeta;
};
return MatrixDim;
}();
export { MatrixDim };
function createUniqueValueGenerator(dim) {
var dimUpper = dim.toUpperCase();
var defaultValReg = new RegExp("^" + dimUpper + "([0-9]+)$");
var dupBase = 0;
function calcDupBase(val) {
var matchResult;
if (val != null && (matchResult = val.match(defaultValReg))) {
dupBase = mathMax(dupBase, +matchResult[1] + 1);
}
}
function makeUniqueValue() {
return "" + dimUpper + dupBase++;
}
// Duplicated value is allowed, because the `matrix.x/y.data` can be a tree and it's reasonable
// that leaves in different subtrees has the same text. But only the first one is allowed to be
// queried by the text, and the other ones can only be queried by index.
// Additionally, `matrix.x/y.data: [null, null, ...]` is allowed.
function ensureValueUnique(categories, cells) {
// A simple way to deduplicate or handle illegal or not specified values to avoid unexpected behaviors.
// The tree structure should not be broken even if duplicated.
var cateMap = createHashMap();
for (var idx = 0; idx < categories.length; idx++) {
var value = categories[idx];
// value may be set to NullUndefined by users or if illegal.
if (value == null || cateMap.get(value) != null) {
// Still display the original option.value if duplicated, but loose the ability to query by text.
categories[idx] = value = makeUniqueValue();
cells[idx].option = defaults({
value: value
}, cells[idx].option);
}
cateMap.set(value, true);
}
}
return {
calcDupBase: calcDupBase,
ensureValueUnique: ensureValueUnique
};
}
+156
View File
@@ -0,0 +1,156 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import ComponentModel from '../../model/Component.js';
import Model from '../../model/Model.js';
import { MatrixDim } from './MatrixDim.js';
import { MatrixBodyCorner } from './MatrixBodyCorner.js';
import tokens from '../../visual/tokens.js';
var defaultLabelOption = {
show: true,
color: tokens.color.secondary,
// overflow: 'truncate',
overflow: 'break',
lineOverflow: 'truncate',
padding: [2, 3, 2, 3],
// Prefer to use `padding`, rather than distance.
distance: 0
};
function makeDefaultCellItemStyleOption(isCorner) {
return {
color: 'none',
borderWidth: 1,
borderColor: isCorner ? 'none' : tokens.color.borderTint
};
}
;
var defaultDimOption = {
show: true,
label: defaultLabelOption,
itemStyle: makeDefaultCellItemStyleOption(false),
silent: undefined,
dividerLineStyle: {
width: 1,
color: tokens.color.border
}
};
var defaultBodyOption = {
label: defaultLabelOption,
itemStyle: makeDefaultCellItemStyleOption(false),
silent: undefined
};
var defaultCornerOption = {
label: defaultLabelOption,
itemStyle: makeDefaultCellItemStyleOption(true),
silent: undefined
};
var defaultMatrixOption = {
// As a most basic coord sys, `z` should be lower than
// other series and coord sys, such as, grid.
z: -50,
left: '10%',
top: '10%',
right: '10%',
bottom: '10%',
x: defaultDimOption,
y: defaultDimOption,
body: defaultBodyOption,
corner: defaultCornerOption,
backgroundStyle: {
color: 'none',
borderColor: tokens.color.axisLine,
borderWidth: 1
},
triggerEvent: false
};
var MatrixModel = /** @class */function (_super) {
__extends(MatrixModel, _super);
function MatrixModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = MatrixModel.type;
return _this;
}
MatrixModel.prototype.optionUpdated = function () {
// Simply re-create all to follow model changes.
var dimModels = this._dimModels = {
// Do not use matrixModel as the parent model, for preventing from cascade-fetching options to it.
x: new MatrixDimensionModel(this.get('x', true) || {}),
y: new MatrixDimensionModel(this.get('y', true) || {})
};
dimModels.x.option.type = dimModels.y.option.type = 'category';
var xDim = dimModels.x.dim = new MatrixDim('x', dimModels.x);
var yDim = dimModels.y.dim = new MatrixDim('y', dimModels.y);
var dims = {
x: xDim,
y: yDim
};
this._body = new MatrixBodyCorner('body', new Model(this.getShallow('body')), dims);
this._corner = new MatrixBodyCorner('corner', new Model(this.getShallow('corner')), dims);
};
MatrixModel.prototype.getDimensionModel = function (dim) {
return this._dimModels[dim];
};
MatrixModel.prototype.getBody = function () {
return this._body;
};
MatrixModel.prototype.getCorner = function () {
return this._corner;
};
MatrixModel.type = 'matrix';
MatrixModel.layoutMode = 'box';
MatrixModel.defaultOption = defaultMatrixOption;
return MatrixModel;
}(ComponentModel);
var MatrixDimensionModel = /** @class */function (_super) {
__extends(MatrixDimensionModel, _super);
function MatrixDimensionModel() {
return _super !== null && _super.apply(this, arguments) || this;
}
MatrixDimensionModel.prototype.getOrdinalMeta = function () {
return this.dim.getOrdinalMeta();
};
return MatrixDimensionModel;
}(Model);
export { MatrixDimensionModel };
export default MatrixModel;
+295
View File
@@ -0,0 +1,295 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { eqNaN, isArray, isNumber } from 'zrender/lib/core/util.js';
import { WH, XY } from '../../util/graphic.js';
import { mathMax, mathMin } from '../../util/number.js';
export var MatrixCellLayoutInfoType = {
level: 1,
leaf: 2,
nonLeaf: 3
};
/**
* @public Public to users in `chart.convertFromPixel`.
*/
export var MatrixClampOption = {
// No clamp, be falsy, equals to null/undefined. It means if the input part is
// null/undefined/NaN/outOfBoundary, the result part is NaN, rather than clamp to
// the boundary of the matrix.
none: 0,
// Clamp, where null/undefined/NaN/outOfBoundary can be used to cover the entire row/column.
all: 1,
body: 2,
corner: 3
};
/**
* For the x direction,
* - find dimension cell from `xMatrixDim`,
* - If `xDimCell` or `yDimCell` is not a leaf, return the non-leaf cell itself.
* - otherwise find level from `yMatrixDim`.
* - otherwise return `NullUndefined`.
*
* For the y direction, it's the opposite.
*/
export function coordDataToAllCellLevelLayout(coordValue, dims, thisDimIdx // 0 | 1
) {
// Find in body.
var result = dims[XY[thisDimIdx]].getCell(coordValue);
// Find in corner or dimension area.
if (!result && isNumber(coordValue) && coordValue < 0) {
result = dims[XY[1 - thisDimIdx]].getUnitLayoutInfo(thisDimIdx, Math.round(coordValue));
}
return result;
}
export function resetXYLocatorRange(out) {
var rg = out || [];
rg[0] = rg[0] || [];
rg[1] = rg[1] || [];
rg[0][0] = rg[0][1] = rg[1][0] = rg[1][1] = NaN;
return rg;
}
/**
* If illegal or out of boundary, set NaN to `locOut`. See `isXYLocatorRangeInvalidOnDim`.
* x dimension and y dimension are calculated separately.
*/
export function parseCoordRangeOption(locOut,
// If illegal input or can not find any target, save reason to it.
// Do nothing if `NullUndefined`.
reasonOut, data, dims, clamp) {
// x and y are supported to be handled separately - if one dimension is invalid
// (may be users do not need that), the other one should also be calculated.
parseCoordRangeOptionOnOneDim(locOut[0], reasonOut, clamp, data, dims, 0);
parseCoordRangeOptionOnOneDim(locOut[1], reasonOut, clamp, data, dims, 1);
}
function parseCoordRangeOptionOnOneDim(locDimOut, reasonOut, clamp, data, dims, dimIdx) {
locDimOut[0] = Infinity;
locDimOut[1] = -Infinity;
var dataOnDim = data[dimIdx];
var coordValArr = isArray(dataOnDim) ? dataOnDim : [dataOnDim];
var len = coordValArr.length;
var hasClamp = !!clamp;
if (len >= 1) {
parseCoordRangeOptionOnOneDimOnePart(locDimOut, reasonOut, coordValArr, hasClamp, dims, dimIdx, 0);
if (len > 1) {
// Users may intuitively input the coords like `[[x1, x2, x3], ...]`;
// consider the range as `[x1, x3]` in this case.
parseCoordRangeOptionOnOneDimOnePart(locDimOut, reasonOut, coordValArr, hasClamp, dims, dimIdx, len - 1);
}
} else {
if (process.env.NODE_ENV !== 'production') {
if (reasonOut) {
reasonOut.push('Should be like [["x1", "x2"], ["y1", "y2"]], or ["x1", "y1"], rather than empty.');
}
}
locDimOut[0] = locDimOut[1] = NaN;
}
if (hasClamp) {
// null/undefined/NaN or illegal data represents the entire row/column;
// Cover the entire locator regardless of body or corner, and confine it later.
var locLowerBound = -dims[XY[1 - dimIdx]].getLocatorCount(dimIdx);
var locUpperBound = dims[XY[dimIdx]].getLocatorCount(dimIdx) - 1;
if (clamp === MatrixClampOption.body) {
locLowerBound = mathMax(0, locLowerBound);
} else if (clamp === MatrixClampOption.corner) {
locUpperBound = mathMin(-1, locUpperBound);
}
if (locUpperBound < locLowerBound) {
// Also considered that both x and y has no cell.
locLowerBound = locUpperBound = NaN;
}
if (eqNaN(locDimOut[0])) {
locDimOut[0] = locLowerBound;
}
if (eqNaN(locDimOut[1])) {
locDimOut[1] = locUpperBound;
}
locDimOut[0] = mathMax(mathMin(locDimOut[0], locUpperBound), locLowerBound);
locDimOut[1] = mathMax(mathMin(locDimOut[1], locUpperBound), locLowerBound);
}
}
// The return val must be finite or NaN.
function parseCoordRangeOptionOnOneDimOnePart(locDimOut, reasonOut, coordValArr, hasClamp, dims, dimIdx, partIdx) {
var layout = coordDataToAllCellLevelLayout(coordValArr[partIdx], dims, dimIdx);
if (!layout) {
if (process.env.NODE_ENV !== 'production') {
if (!hasClamp && reasonOut) {
reasonOut.push("Can not find cell by coord[" + dimIdx + "][" + partIdx + "].");
}
}
locDimOut[0] = locDimOut[1] = NaN;
return;
}
var locatorA = layout.id[XY[dimIdx]];
var locatorB = locatorA;
var dimCell = cellLayoutInfoToDimCell(layout);
if (dimCell) {
// Handle non-leaf
locatorB += dimCell.span[XY[dimIdx]] - 1;
}
locDimOut[0] = mathMin(locDimOut[0], locatorA, locatorB);
locDimOut[1] = mathMax(locDimOut[1], locatorA, locatorB);
}
/**
* @param locatorRange Must be the return of `parseCoordRangeOption`,
* where if not NaN, it must be a valid locator.
*/
export function isXYLocatorRangeInvalidOnDim(locatorRange, dimIdx) {
return eqNaN(locatorRange[dimIdx][0]) || eqNaN(locatorRange[dimIdx][1]);
}
// `locatorRange` will be expanded (modified) if an intersection is encountered.
export function resolveXYLocatorRangeByCellMerge(inOutLocatorRange,
// Item indices coorespond to mergeDefList (len: mergeDefListTravelLen).
// Indicating whether each item has be merged into the `locatorRange`
outMergedMarkList, mergeDefList, mergeDefListTravelLen) {
outMergedMarkList = outMergedMarkList || _tmpOutMergedMarkList;
for (var idx = 0; idx < mergeDefListTravelLen; idx++) {
outMergedMarkList[idx] = false;
}
// In most case, cell merging definition list length is smaller than the range extent,
// therefore, to detection intersection, travelling cell merging definition list is probably
// performant than traveling the four edges of the rect formed by the locator range.
while (true) {
var expanded = false;
for (var idx = 0; idx < mergeDefListTravelLen; idx++) {
var mergeDef = mergeDefList[idx];
if (!outMergedMarkList[idx] && mergeDef.cellMergeOwner && expandXYLocatorRangeIfIntersect(inOutLocatorRange, mergeDef.locatorRange)) {
outMergedMarkList[idx] = true;
expanded = true;
}
}
if (!expanded) {
break;
}
}
}
var _tmpOutMergedMarkList = [];
// Return whether intersect.
// `thisLocRange` will be expanded (modified) if an intersection is encountered.
function expandXYLocatorRangeIfIntersect(thisLocRange, otherLocRange) {
if (!locatorRangeIntersectOneDim(thisLocRange[0], otherLocRange[0]) || !locatorRangeIntersectOneDim(thisLocRange[1], otherLocRange[1])) {
return false;
}
thisLocRange[0][0] = mathMin(thisLocRange[0][0], otherLocRange[0][0]);
thisLocRange[0][1] = mathMax(thisLocRange[0][1], otherLocRange[0][1]);
thisLocRange[1][0] = mathMin(thisLocRange[1][0], otherLocRange[1][0]);
thisLocRange[1][1] = mathMax(thisLocRange[1][1], otherLocRange[1][1]);
return true;
}
// Notice: If containing NaN, not intersect.
function locatorRangeIntersectOneDim(locRange1OneDim, locRange2OneDim) {
return locRange1OneDim[1] >= locRange2OneDim[0] && locRange1OneDim[0] <= locRange2OneDim[1];
}
export function fillIdSpanFromLocatorRange(owner, locatorRange) {
owner.id.set(locatorRange[0][0], locatorRange[1][0]);
owner.span.set(locatorRange[0][1] - owner.id.x + 1, locatorRange[1][1] - owner.id.y + 1);
}
export function cloneXYLocatorRange(target, source) {
target[0][0] = source[0][0];
target[0][1] = source[0][1];
target[1][0] = source[1][0];
target[1][1] = source[1][1];
}
/**
* If illegal, the corresponding x/y/width/height is set to `NaN`.
* `x/width` or `y/height` is supported to be calculated separately,
* i.e., one side are NaN, the other side are normal.
* @param oneDimOut only write to `x/width` or `y/height`, depending on `dimIdx`.
*/
export function xyLocatorRangeToRectOneDim(oneDimOut, locRange, dims, dimIdx) {
var layoutMin = coordDataToAllCellLevelLayout(locRange[dimIdx][0], dims, dimIdx);
var layoutMax = coordDataToAllCellLevelLayout(locRange[dimIdx][1], dims, dimIdx);
oneDimOut[XY[dimIdx]] = oneDimOut[WH[dimIdx]] = NaN;
if (layoutMin && layoutMax) {
oneDimOut[XY[dimIdx]] = layoutMin.xy;
oneDimOut[WH[dimIdx]] = layoutMax.xy + layoutMax.wh - layoutMin.xy;
}
}
// No need currently, since `span` is not allowed to be defined directly by users.
// /**
// * If either span x or y is valid and > 1, return parsed span, otherwise return `NullUndefined`.
// */
// export function parseSpanOption(
// spanOptionHost: MatrixCellSpanOptionHost,
// dimCellPair: MatrixCellLayoutInfo[]
// ): Point | NullUndefined {
// const spanX = parseSpanOnDim(spanOptionHost.spanX, dimCellPair[0], 0);
// const spanY = parseSpanOnDim(spanOptionHost.spanY, dimCellPair[1], 1);
// if (!eqNaN(spanX) || !eqNaN(spanY)) {
// return new Point(spanX || 1, spanY || 1);
// }
// function parseSpanOnDim(spanOption: unknown, dimCell: MatrixCellLayoutInfo, dimIdx: number): number {
// if (!isNumber(spanOption)) {
// return NaN;
// }
// // Ensure positive integer (not NaN) to avoid dead loop.
// const span = mathMax(1, Math.round(spanOption || 1)) || 1;
// // Clamp, and consider may also be specified as `Infinity` to span the entire col/row.
// return mathMin(span, mathMax(1, dimCell.dim.getLocatorCount(dimIdx) - dimCell.id[XY[dimIdx]]));
// }
// }
/**
* @usage To get/set on dimension, use:
* `xyVal[XY[dim]] = val;` // set on this dimension.
* `xyVal[XY[1 - dim]] = val;` // set on the perpendicular dimension.
*/
export function setDimXYValue(out, dimIdx,
// 0 | 1
valueOnThisDim, valueOnOtherDim) {
out[XY[dimIdx]] = valueOnThisDim;
out[XY[1 - dimIdx]] = valueOnOtherDim;
return out;
}
/**
* Return NullUndefined if not dimension cell.
*/
function cellLayoutInfoToDimCell(cellLayoutInfo) {
return cellLayoutInfo && (cellLayoutInfo.type === MatrixCellLayoutInfoType.leaf || cellLayoutInfo.type === MatrixCellLayoutInfoType.nonLeaf) ? cellLayoutInfo : null;
}
export function createNaNRectLike() {
return {
x: NaN,
y: NaN,
width: NaN,
height: NaN
};
}
+63
View File
@@ -0,0 +1,63 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
export default function matrixPrepareCustom(coordSys) {
var rect = coordSys.getRect();
return {
coordSys: {
type: 'matrix',
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height
},
api: {
coord: function (data, opt) {
return coordSys.dataToPoint(data, opt);
},
layout: function (data, opt) {
return coordSys.dataToLayout(data, opt);
}
}
};
}
+114
View File
@@ -0,0 +1,114 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import ComponentModel from '../../model/Component.js';
import makeStyleMapper from '../../model/mixin/makeStyleMapper.js';
import * as numberUtil from '../../util/number.js';
import { AxisModelCommonMixin } from '../axisModelCommonMixin.js';
var ParallelAxisModel = /** @class */function (_super) {
__extends(ParallelAxisModel, _super);
function ParallelAxisModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = ParallelAxisModel.type;
/**
* @readOnly
*/
_this.activeIntervals = [];
return _this;
}
ParallelAxisModel.prototype.getAreaSelectStyle = function () {
return makeStyleMapper([['fill', 'color'], ['lineWidth', 'borderWidth'], ['stroke', 'borderColor'], ['width', 'width'], ['opacity', 'opacity']
// Option decal is in `DecalObject` but style.decal is in `PatternObject`.
// So do not transfer decal directly.
])(this.getModel('areaSelectStyle'));
};
/**
* The code of this feature is put on AxisModel but not ParallelAxis,
* because axisModel can be alive after echarts updating but instance of
* ParallelAxis having been disposed. this._activeInterval should be kept
* when action dispatched (i.e. legend click).
*
* @param intervals `interval.length === 0` means set all active.
*/
ParallelAxisModel.prototype.setActiveIntervals = function (intervals) {
var activeIntervals = this.activeIntervals = zrUtil.clone(intervals);
// Normalize
if (activeIntervals) {
for (var i = activeIntervals.length - 1; i >= 0; i--) {
numberUtil.asc(activeIntervals[i]);
}
}
};
/**
* @param value When only attempting detect whether 'no activeIntervals set',
* `value` is not needed to be input.
*/
ParallelAxisModel.prototype.getActiveState = function (value) {
var activeIntervals = this.activeIntervals;
if (!activeIntervals.length) {
return 'normal';
}
if (value == null || isNaN(+value)) {
return 'inactive';
}
// Simple optimization
if (activeIntervals.length === 1) {
var interval = activeIntervals[0];
if (interval[0] <= value && value <= interval[1]) {
return 'active';
}
} else {
for (var i = 0, len = activeIntervals.length; i < len; i++) {
if (activeIntervals[i][0] <= value && value <= activeIntervals[i][1]) {
return 'active';
}
}
}
return 'inactive';
};
return ParallelAxisModel;
}(ComponentModel);
zrUtil.mixin(ParallelAxisModel, AxisModelCommonMixin);
export default ParallelAxisModel;
+392
View File
@@ -0,0 +1,392 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
/**
* Parallel Coordinates
* <https://en.wikipedia.org/wiki/Parallel_coordinates>
*/
import { each, createHashMap, clone } from 'zrender/lib/core/util.js';
import * as matrix from 'zrender/lib/core/matrix.js';
import * as layoutUtil from '../../util/layout.js';
import * as axisHelper from '../../coord/axisHelper.js';
import ParallelAxis from './ParallelAxis.js';
import * as graphic from '../../util/graphic.js';
import { mathCeil, mathFloor, mathMax, mathMin, mathPI, round } from '../../util/number.js';
import sliderMove from '../../component/helper/sliderMove.js';
import { COORD_SYS_TYPE_PARALLEL } from './ParallelModel.js';
import { scaleCalcNice } from '../axisNiceTicks.js';
import { AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE, scaleRawExtentInfoCreate } from '../scaleRawExtentInfo.js';
var Parallel = /** @class */function () {
function Parallel(parallelModel, ecModel, api) {
this.type = COORD_SYS_TYPE_PARALLEL;
/**
* key: dimension
*/
this._axesMap = createHashMap();
/**
* key: dimension
* value: {position: [], rotation, }
*/
this._axesLayout = {};
this.dimensions = parallelModel.dimensions;
this._model = parallelModel;
this._init(parallelModel, ecModel, api);
}
Parallel.prototype._init = function (parallelModel, ecModel, api) {
var dimensions = parallelModel.dimensions;
var parallelAxisIndex = parallelModel.parallelAxisIndex;
each(dimensions, function (dim, idx) {
var axisIndex = parallelAxisIndex[idx];
var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
var axisType = axisHelper.determineAxisType(axisModel);
var axis = this._axesMap.set(dim, new ParallelAxis(dim, axisHelper.createScaleByModel(axisModel, axisType, false), [0, 0], axisType, axisIndex));
axis.onBand = axisHelper.isAxisOnBand(axis.scale, axisModel);
axis.inverse = axisModel.get('inverse');
// Injection
axisModel.axis = axis;
axis.model = axisModel;
axis.coordinateSystem = axisModel.coordinateSystem = this;
}, this);
};
/**
* Update axis scale after data processed
*/
Parallel.prototype.update = function (ecModel, api) {
each(this.dimensions, function (dim) {
var axis = this._axesMap.get(dim);
scaleRawExtentInfoCreate(axis, AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE);
scaleCalcNice(axis);
}, this);
};
Parallel.prototype.containPoint = function (point) {
var layoutInfo = this._makeLayoutInfo();
var axisBase = layoutInfo.axisBase;
var layoutBase = layoutInfo.layoutBase;
var pixelDimIndex = layoutInfo.pixelDimIndex;
var pAxis = point[1 - pixelDimIndex];
var pLayout = point[pixelDimIndex];
return pAxis >= axisBase && pAxis <= axisBase + layoutInfo.axisLength && pLayout >= layoutBase && pLayout <= layoutBase + layoutInfo.layoutLength;
};
Parallel.prototype.getModel = function () {
return this._model;
};
/**
* Resize the parallel coordinate system.
*/
Parallel.prototype.resize = function (parallelModel, api) {
var refContainer = layoutUtil.createBoxLayoutReference(parallelModel, api).refContainer;
this._rect = layoutUtil.getLayoutRect(parallelModel.getBoxLayoutParams(), refContainer);
this._layoutAxes();
};
Parallel.prototype.getRect = function () {
return this._rect;
};
Parallel.prototype._makeLayoutInfo = function () {
var parallelModel = this._model;
var rect = this._rect;
var xy = ['x', 'y'];
var wh = ['width', 'height'];
var layout = parallelModel.get('layout');
var pixelDimIndex = layout === 'horizontal' ? 0 : 1;
var layoutLength = rect[wh[pixelDimIndex]];
var layoutExtent = [0, layoutLength];
var axisCount = this.dimensions.length;
var axisExpandWidth = restrict(parallelModel.get('axisExpandWidth'), layoutExtent);
var axisExpandCount = restrict(parallelModel.get('axisExpandCount') || 0, [0, axisCount]);
var axisExpandable = parallelModel.get('axisExpandable') && axisCount > 3 && axisCount > axisExpandCount && axisExpandCount > 1 && axisExpandWidth > 0 && layoutLength > 0;
// `axisExpandWindow` is According to the coordinates of [0, axisExpandLength],
// for sake of consider the case that axisCollapseWidth is 0 (when screen is narrow),
// where collapsed axes should be overlapped.
var axisExpandWindow = parallelModel.get('axisExpandWindow');
var winSize;
if (!axisExpandWindow) {
winSize = restrict(axisExpandWidth * (axisExpandCount - 1), layoutExtent);
var axisExpandCenter = parallelModel.get('axisExpandCenter') || mathFloor(axisCount / 2);
axisExpandWindow = [axisExpandWidth * axisExpandCenter - winSize / 2];
axisExpandWindow[1] = axisExpandWindow[0] + winSize;
} else {
winSize = restrict(axisExpandWindow[1] - axisExpandWindow[0], layoutExtent);
axisExpandWindow[1] = axisExpandWindow[0] + winSize;
}
var axisCollapseWidth = (layoutLength - winSize) / (axisCount - axisExpandCount);
// Avoid axisCollapseWidth is too small.
axisCollapseWidth < 3 && (axisCollapseWidth = 0);
// Find the first and last indices > ewin[0] and < ewin[1].
var winInnerIndices = [mathFloor(round(axisExpandWindow[0] / axisExpandWidth, 1)) + 1, mathCeil(round(axisExpandWindow[1] / axisExpandWidth, 1)) - 1];
// Pos in ec coordinates.
var axisExpandWindow0Pos = axisCollapseWidth / axisExpandWidth * axisExpandWindow[0];
return {
layout: layout,
pixelDimIndex: pixelDimIndex,
layoutBase: rect[xy[pixelDimIndex]],
layoutLength: layoutLength,
axisBase: rect[xy[1 - pixelDimIndex]],
axisLength: rect[wh[1 - pixelDimIndex]],
axisExpandable: axisExpandable,
axisExpandWidth: axisExpandWidth,
axisCollapseWidth: axisCollapseWidth,
axisExpandWindow: axisExpandWindow,
axisCount: axisCount,
winInnerIndices: winInnerIndices,
axisExpandWindow0Pos: axisExpandWindow0Pos
};
};
Parallel.prototype._layoutAxes = function () {
var rect = this._rect;
var axes = this._axesMap;
var dimensions = this.dimensions;
var layoutInfo = this._makeLayoutInfo();
var layout = layoutInfo.layout;
axes.each(function (axis) {
var axisExtent = [0, layoutInfo.axisLength];
var idx = axis.inverse ? 1 : 0;
axis.setExtent(axisExtent[idx], axisExtent[1 - idx]);
});
each(dimensions, function (dim, idx) {
var posInfo = (layoutInfo.axisExpandable ? layoutAxisWithExpand : layoutAxisWithoutExpand)(idx, layoutInfo);
var positionTable = {
horizontal: {
x: posInfo.position,
y: layoutInfo.axisLength
},
vertical: {
x: 0,
y: posInfo.position
}
};
var rotationTable = {
horizontal: mathPI / 2,
vertical: 0
};
var position = [positionTable[layout].x + rect.x, positionTable[layout].y + rect.y];
var rotation = rotationTable[layout];
var transform = matrix.create();
matrix.rotate(transform, transform, rotation);
matrix.translate(transform, transform, position);
// TODO
// tick layout info
// TODO
// update dimensions info based on axis order.
this._axesLayout[dim] = {
position: position,
rotation: rotation,
transform: transform,
axisNameAvailableWidth: posInfo.axisNameAvailableWidth,
axisLabelShow: posInfo.axisLabelShow,
nameTruncateMaxWidth: posInfo.nameTruncateMaxWidth,
tickDirection: 1,
labelDirection: 1
};
}, this);
};
/**
* Get axis by dim.
*/
Parallel.prototype.getAxis = function (dim) {
return this._axesMap.get(dim);
};
/**
* Convert a dim value of a single item of series data to Point.
*/
Parallel.prototype.dataToPoint = function (value, dim) {
return this.axisCoordToPoint(this._axesMap.get(dim).dataToCoord(value), dim);
};
/**
* Travel data for one time, get activeState of each data item.
* @param start the start dataIndex that travel from.
* @param end the next dataIndex of the last dataIndex will be travel.
*/
Parallel.prototype.eachActiveState = function (data, callback, start, end) {
start == null && (start = 0);
end == null && (end = data.count());
var axesMap = this._axesMap;
var dimensions = this.dimensions;
var dataDimensions = [];
var axisModels = [];
each(dimensions, function (axisDim) {
dataDimensions.push(data.mapDimension(axisDim));
axisModels.push(axesMap.get(axisDim).model);
});
var hasActiveSet = this.hasAxisBrushed();
for (var dataIndex = start; dataIndex < end; dataIndex++) {
var activeState = void 0;
if (!hasActiveSet) {
activeState = 'normal';
} else {
activeState = 'active';
var values = data.getValues(dataDimensions, dataIndex);
for (var j = 0, lenj = dimensions.length; j < lenj; j++) {
var state = axisModels[j].getActiveState(values[j]);
if (state === 'inactive') {
activeState = 'inactive';
break;
}
}
}
callback(activeState, dataIndex);
}
};
/**
* Whether has any activeSet.
*/
Parallel.prototype.hasAxisBrushed = function () {
var dimensions = this.dimensions;
var axesMap = this._axesMap;
var hasActiveSet = false;
for (var j = 0, lenj = dimensions.length; j < lenj; j++) {
if (axesMap.get(dimensions[j]).model.getActiveState() !== 'normal') {
hasActiveSet = true;
}
}
return hasActiveSet;
};
/**
* Convert coords of each axis to Point.
* Return point. For example: [10, 20]
*/
Parallel.prototype.axisCoordToPoint = function (coord, dim) {
var axisLayout = this._axesLayout[dim];
return graphic.applyTransform([coord, 0], axisLayout.transform);
};
/**
* Get axis layout.
*/
Parallel.prototype.getAxisLayout = function (dim) {
return clone(this._axesLayout[dim]);
};
/**
* @return {Object} {axisExpandWindow, delta, behavior: 'jump' | 'slide' | 'none'}.
*/
Parallel.prototype.getSlidedAxisExpandWindow = function (point) {
var layoutInfo = this._makeLayoutInfo();
var pixelDimIndex = layoutInfo.pixelDimIndex;
var axisExpandWindow = layoutInfo.axisExpandWindow.slice();
var winSize = axisExpandWindow[1] - axisExpandWindow[0];
var extent = [0, layoutInfo.axisExpandWidth * (layoutInfo.axisCount - 1)];
// Out of the area of coordinate system.
if (!this.containPoint(point)) {
return {
behavior: 'none',
axisExpandWindow: axisExpandWindow
};
}
// Convert the point from global to expand coordinates.
var pointCoord = point[pixelDimIndex] - layoutInfo.layoutBase - layoutInfo.axisExpandWindow0Pos;
// For dragging operation convenience, the window should not be
// slided when mouse is the center area of the window.
var delta;
var behavior = 'slide';
var axisCollapseWidth = layoutInfo.axisCollapseWidth;
var triggerArea = this._model.get('axisExpandSlideTriggerArea');
// But consider touch device, jump is necessary.
var useJump = triggerArea[0] != null;
if (axisCollapseWidth) {
if (useJump && axisCollapseWidth && pointCoord < winSize * triggerArea[0]) {
behavior = 'jump';
delta = pointCoord - winSize * triggerArea[2];
} else if (useJump && axisCollapseWidth && pointCoord > winSize * (1 - triggerArea[0])) {
behavior = 'jump';
delta = pointCoord - winSize * (1 - triggerArea[2]);
} else {
(delta = pointCoord - winSize * triggerArea[1]) >= 0 && (delta = pointCoord - winSize * (1 - triggerArea[1])) <= 0 && (delta = 0);
}
delta *= layoutInfo.axisExpandWidth / axisCollapseWidth;
delta ? sliderMove(delta, axisExpandWindow, extent, 'all')
// Avoid nonsense triger on mousemove.
: behavior = 'none';
}
// When screen is too narrow, make it visible and slidable, although it is hard to interact.
else {
var winSize2 = axisExpandWindow[1] - axisExpandWindow[0];
var pos = extent[1] * pointCoord / winSize2;
axisExpandWindow = [mathMax(0, pos - winSize2 / 2)];
axisExpandWindow[1] = mathMin(extent[1], axisExpandWindow[0] + winSize2);
axisExpandWindow[0] = axisExpandWindow[1] - winSize2;
}
return {
axisExpandWindow: axisExpandWindow,
behavior: behavior
};
};
return Parallel;
}();
function restrict(len, extent) {
return mathMin(mathMax(len, extent[0]), extent[1]);
}
function layoutAxisWithoutExpand(axisIndex, layoutInfo) {
var step = layoutInfo.layoutLength / (layoutInfo.axisCount - 1);
return {
position: step * axisIndex,
axisNameAvailableWidth: step,
axisLabelShow: true
};
}
function layoutAxisWithExpand(axisIndex, layoutInfo) {
var layoutLength = layoutInfo.layoutLength;
var axisExpandWidth = layoutInfo.axisExpandWidth;
var axisCount = layoutInfo.axisCount;
var axisCollapseWidth = layoutInfo.axisCollapseWidth;
var winInnerIndices = layoutInfo.winInnerIndices;
var position;
var axisNameAvailableWidth = axisCollapseWidth;
var axisLabelShow = false;
var nameTruncateMaxWidth;
if (axisIndex < winInnerIndices[0]) {
position = axisIndex * axisCollapseWidth;
nameTruncateMaxWidth = axisCollapseWidth;
} else if (axisIndex <= winInnerIndices[1]) {
position = layoutInfo.axisExpandWindow0Pos + axisIndex * axisExpandWidth - layoutInfo.axisExpandWindow[0];
axisNameAvailableWidth = axisExpandWidth;
axisLabelShow = true;
} else {
position = layoutLength - (axisCount - 1 - axisIndex) * axisCollapseWidth;
nameTruncateMaxWidth = axisCollapseWidth;
}
return {
position: position,
axisNameAvailableWidth: axisNameAvailableWidth,
axisLabelShow: axisLabelShow,
nameTruncateMaxWidth: nameTruncateMaxWidth
};
}
export default Parallel;
+59
View File
@@ -0,0 +1,59 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import Axis from '../Axis.js';
var ParallelAxis = /** @class */function (_super) {
__extends(ParallelAxis, _super);
function ParallelAxis(dim, scale, coordExtent, axisType, axisIndex) {
var _this = _super.call(this, dim, scale, coordExtent) || this;
_this.type = axisType || 'value';
_this.axisIndex = axisIndex;
return _this;
}
ParallelAxis.prototype.isHorizontal = function () {
return this.coordinateSystem.getModel().get('layout') !== 'horizontal';
};
return ParallelAxis;
}(Axis);
export default ParallelAxis;
+124
View File
@@ -0,0 +1,124 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import ComponentModel from '../../model/Component.js';
export var COORD_SYS_TYPE_PARALLEL = 'parallel';
export var COMPONENT_TYPE_PARALLEL = COORD_SYS_TYPE_PARALLEL;
var ParallelModel = /** @class */function (_super) {
__extends(ParallelModel, _super);
function ParallelModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = ParallelModel.type;
return _this;
}
ParallelModel.prototype.init = function () {
_super.prototype.init.apply(this, arguments);
this.mergeOption({});
};
ParallelModel.prototype.mergeOption = function (newOption) {
var thisOption = this.option;
newOption && zrUtil.merge(thisOption, newOption, true);
this._initDimensions();
};
/**
* Whether series or axis is in this coordinate system.
*/
ParallelModel.prototype.contains = function (model, ecModel) {
var parallelIndex = model.get('parallelIndex');
return parallelIndex != null && ecModel.getComponent('parallel', parallelIndex) === this;
};
ParallelModel.prototype.setAxisExpand = function (opt) {
zrUtil.each(['axisExpandable', 'axisExpandCenter', 'axisExpandCount', 'axisExpandWidth', 'axisExpandWindow'], function (name) {
if (opt.hasOwnProperty(name)) {
// @ts-ignore FIXME: why "never" inferred in this.option[name]?
this.option[name] = opt[name];
}
}, this);
};
ParallelModel.prototype._initDimensions = function () {
var dimensions = this.dimensions = [];
var parallelAxisIndex = this.parallelAxisIndex = [];
var axisModels = zrUtil.filter(this.ecModel.queryComponents({
mainType: 'parallelAxis'
}), function (axisModel) {
// Can not use this.contains here, because
// initialization has not been completed yet.
return (axisModel.get('parallelIndex') || 0) === this.componentIndex;
}, this);
zrUtil.each(axisModels, function (axisModel) {
dimensions.push('dim' + axisModel.get('dim'));
parallelAxisIndex.push(axisModel.componentIndex);
});
};
ParallelModel.type = COMPONENT_TYPE_PARALLEL;
ParallelModel.dependencies = ['parallelAxis'];
ParallelModel.layoutMode = 'box';
ParallelModel.defaultOption = {
// zlevel: 0,
z: 0,
left: 80,
top: 60,
right: 80,
bottom: 60,
// width: {totalWidth} - left - right,
// height: {totalHeight} - top - bottom,
layout: 'horizontal',
// FIXME
// naming?
axisExpandable: false,
axisExpandCenter: null,
axisExpandCount: 0,
axisExpandWidth: 50,
axisExpandRate: 17,
axisExpandDebounce: 50,
// [out, in, jumpTarget]. In percentage. If use [null, 0.05], null means full.
// Do not doc to user until necessary.
axisExpandSlideTriggerArea: [-0.15, 0.05, 0.4],
axisExpandTriggerOn: 'click',
parallelAxisDefault: null
};
return ParallelModel;
}(ComponentModel);
export default ParallelModel;
+79
View File
@@ -0,0 +1,79 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
/**
* Parallel coordinate system creator.
*/
import Parallel from './Parallel.js';
import { COMPONENT_TYPE_PARALLEL, COORD_SYS_TYPE_PARALLEL } from './ParallelModel.js';
import { SINGLE_REFERRING } from '../../util/model.js';
import { each } from 'zrender/lib/core/util.js';
import { associateSeriesWithAxis } from '../axisStatistics.js';
function createParallelCoordSys(ecModel, api) {
var coordSysList = [];
ecModel.eachComponent(COMPONENT_TYPE_PARALLEL, function (parallelModel, idx) {
var coordSys = new Parallel(parallelModel, ecModel, api);
coordSys.name = 'parallel_' + idx;
coordSys.resize(parallelModel, api);
parallelModel.coordinateSystem = coordSys;
coordSys.model = parallelModel;
coordSysList.push(coordSys);
});
// Inject the coordinateSystems into seriesModel
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.get('coordinateSystem') === COORD_SYS_TYPE_PARALLEL) {
var parallelModel = seriesModel.getReferringComponents(COMPONENT_TYPE_PARALLEL, SINGLE_REFERRING).models[0];
var parallel_1 = seriesModel.coordinateSystem = parallelModel.coordinateSystem;
if (parallel_1) {
each(parallel_1.dimensions, function (dim) {
associateSeriesWithAxis(parallel_1.getAxis(dim), seriesModel, COORD_SYS_TYPE_PARALLEL);
});
}
}
});
return coordSysList;
}
var parallelCoordSysCreator = {
create: createParallelCoordSys
};
export default parallelCoordSysCreator;
+84
View File
@@ -0,0 +1,84 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import * as modelUtil from '../../util/model.js';
export default function parallelPreprocessor(option) {
createParallelIfNeeded(option);
mergeAxisOptionFromParallel(option);
}
/**
* Create a parallel coordinate if not exists.
* @inner
*/
function createParallelIfNeeded(option) {
if (option.parallel) {
return;
}
var hasParallelSeries = false;
zrUtil.each(option.series, function (seriesOpt) {
if (seriesOpt && seriesOpt.type === 'parallel') {
hasParallelSeries = true;
}
});
if (hasParallelSeries) {
option.parallel = [{}];
}
}
/**
* Merge aixs definition from parallel option (if exists) to axis option.
* @inner
*/
function mergeAxisOptionFromParallel(option) {
var axes = modelUtil.normalizeToArray(option.parallelAxis);
zrUtil.each(axes, function (axisOption) {
if (!zrUtil.isObject(axisOption)) {
return;
}
var parallelIndex = axisOption.parallelIndex || 0;
var parallelOption = modelUtil.normalizeToArray(option.parallel)[parallelIndex];
if (parallelOption && parallelOption.parallelAxisDefault) {
zrUtil.merge(axisOption, parallelOption.parallelAxisDefault, false);
}
});
}
+111
View File
@@ -0,0 +1,111 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as textContain from 'zrender/lib/contain/text.js';
import Axis from '../Axis.js';
import { makeInner } from '../../util/model.js';
var inner = makeInner();
var AngleAxis = /** @class */function (_super) {
__extends(AngleAxis, _super);
function AngleAxis(scale, angleExtent) {
return _super.call(this, 'angle', scale, angleExtent || [0, 360]) || this;
}
AngleAxis.prototype.pointToData = function (point, clamp) {
return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1];
};
/**
* Only be called in category axis.
* Angle axis uses text height to decide interval
*
* @override
* @return {number} Auto interval for cateogry axis tick and label
*/
AngleAxis.prototype.calculateCategoryInterval = function () {
var axis = this;
var labelModel = axis.getLabelModel();
var ordinalScale = axis.scale;
var ordinalExtent = ordinalScale.getExtent();
// Providing this method is for optimization:
// avoid generating a long array by `getTicks`
// in large category data case.
var tickCount = ordinalScale.count();
if (ordinalExtent[1] - ordinalExtent[0] < 1) {
return 0;
}
var tickValue = ordinalExtent[0];
var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);
var unitH = Math.abs(unitSpan);
// Not precise, just use height as text width
// and each distance from axis line yet.
var rect = textContain.getBoundingRect(tickValue == null ? '' : tickValue + '', labelModel.getFont(), 'center', 'top');
var maxH = Math.max(rect.height, 7);
var dh = maxH / unitH;
// 0/0 is NaN, 1/0 is Infinity.
isNaN(dh) && (dh = Infinity);
var interval = Math.max(0, Math.floor(dh));
var cache = inner(axis.model);
var lastAutoInterval = cache.lastAutoInterval;
var lastTickCount = cache.lastTickCount;
// Use cache to keep interval stable while moving zoom window,
// otherwise the calculated interval might jitter when the zoom
// window size is close to the interval-changing size.
if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1
// Always choose the bigger one, otherwise the critical
// point is not the same when zooming in or zooming out.
&& lastAutoInterval > interval) {
interval = lastAutoInterval;
}
// Only update cache if cache not used, otherwise the
// changing of interval is too insensitive.
else {
cache.lastTickCount = tickCount;
cache.lastAutoInterval = interval;
}
return interval;
};
return AngleAxis;
}(Axis);
AngleAxis.prototype.dataToAngle = Axis.prototype.dataToCoord;
AngleAxis.prototype.angleToData = Axis.prototype.coordToData;
export default AngleAxis;
+83
View File
@@ -0,0 +1,83 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import ComponentModel from '../../model/Component.js';
import { AxisModelCommonMixin } from '../axisModelCommonMixin.js';
import { SINGLE_REFERRING } from '../../util/model.js';
var PolarAxisModel = /** @class */function (_super) {
__extends(PolarAxisModel, _super);
function PolarAxisModel() {
return _super !== null && _super.apply(this, arguments) || this;
}
PolarAxisModel.prototype.getCoordSysModel = function () {
return this.getReferringComponents('polar', SINGLE_REFERRING).models[0];
};
PolarAxisModel.type = 'polarAxis';
return PolarAxisModel;
}(ComponentModel);
zrUtil.mixin(PolarAxisModel, AxisModelCommonMixin);
export { PolarAxisModel };
var AngleAxisModel = /** @class */function (_super) {
__extends(AngleAxisModel, _super);
function AngleAxisModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = AngleAxisModel.type;
return _this;
}
AngleAxisModel.type = 'angleAxis';
return AngleAxisModel;
}(PolarAxisModel);
export { AngleAxisModel };
var RadiusAxisModel = /** @class */function (_super) {
__extends(RadiusAxisModel, _super);
function RadiusAxisModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = RadiusAxisModel.type;
return _this;
}
RadiusAxisModel.type = 'radiusAxis';
return RadiusAxisModel;
}(PolarAxisModel);
export { RadiusAxisModel };
+230
View File
@@ -0,0 +1,230 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 RadiusAxis from './RadiusAxis.js';
import AngleAxis from './AngleAxis.js';
import { COORD_SYS_TYPE_POLAR } from './PolarModel.js';
export var polarDimensions = ['radius', 'angle'];
var Polar = /** @class */function () {
function Polar(name) {
this.dimensions = polarDimensions;
this.type = COORD_SYS_TYPE_POLAR;
/**
* x of polar center
*/
this.cx = 0;
/**
* y of polar center
*/
this.cy = 0;
this._radiusAxis = new RadiusAxis();
this._angleAxis = new AngleAxis();
this.axisPointerEnabled = true;
this.name = name || '';
this._radiusAxis.polar = this._angleAxis.polar = this;
}
/**
* If contain coord
*/
Polar.prototype.containPoint = function (point) {
var coord = this.pointToCoord(point);
return this._radiusAxis.contain(coord[0]) && this._angleAxis.contain(coord[1]);
};
/**
* If contain data
*/
Polar.prototype.containData = function (data) {
return this._radiusAxis.containData(data[0]) && this._angleAxis.containData(data[1]);
};
Polar.prototype.getAxis = function (dim) {
var key = '_' + dim + 'Axis';
return this[key];
};
Polar.prototype.getAxes = function () {
return [this._radiusAxis, this._angleAxis];
};
/**
* Get axes by type of scale
*/
Polar.prototype.getAxesByScale = function (scaleType) {
var axes = [];
var angleAxis = this._angleAxis;
var radiusAxis = this._radiusAxis;
angleAxis.scale.type === scaleType && axes.push(angleAxis);
radiusAxis.scale.type === scaleType && axes.push(radiusAxis);
return axes;
};
Polar.prototype.getAngleAxis = function () {
return this._angleAxis;
};
Polar.prototype.getRadiusAxis = function () {
return this._radiusAxis;
};
Polar.prototype.getOtherAxis = function (axis) {
var angleAxis = this._angleAxis;
return axis === angleAxis ? this._radiusAxis : angleAxis;
};
/**
* Base axis will be used on stacking.
*/
Polar.prototype.getBaseAxis = function () {
return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAngleAxis();
};
Polar.prototype.getTooltipAxes = function (dim) {
var baseAxis = dim != null && dim !== 'auto' ? this.getAxis(dim) : this.getBaseAxis();
return {
baseAxes: [baseAxis],
otherAxes: [this.getOtherAxis(baseAxis)]
};
};
/**
* Convert a single data item to (x, y) point.
* Parameter data is an array which the first element is radius and the second is angle
*/
Polar.prototype.dataToPoint = function (data, clamp, out) {
return this.coordToPoint([
// Must be the same order as polarDimensions
this._radiusAxis.dataToRadius(data[0], clamp), this._angleAxis.dataToAngle(data[1], clamp)], out);
};
/**
* Convert a (x, y) point to data
*/
Polar.prototype.pointToData = function (point, clamp, out) {
out = out || [];
var coord = this.pointToCoord(point);
// Must be the same order as polarDimensions
out[0] = this._radiusAxis.radiusToData(coord[0], clamp);
out[1] = this._angleAxis.angleToData(coord[1], clamp);
return out;
};
/**
* Convert a (x, y) point to (radius, angle) coord
*/
Polar.prototype.pointToCoord = function (point) {
var dx = point[0] - this.cx;
var dy = point[1] - this.cy;
var angleAxis = this.getAngleAxis();
var extent = angleAxis.getExtent();
var minAngle = Math.min(extent[0], extent[1]);
var maxAngle = Math.max(extent[0], extent[1]);
// Fix fixed extent in polarCreator
// FIXME
angleAxis.inverse ? minAngle = maxAngle - 360 : maxAngle = minAngle + 360;
var radius = Math.sqrt(dx * dx + dy * dy);
dx /= radius;
dy /= radius;
var radian = Math.atan2(-dy, dx) / Math.PI * 180;
// move to angleExtent
var dir = radian < minAngle ? 1 : -1;
while (radian < minAngle || radian > maxAngle) {
radian += dir * 360;
}
return [radius, radian];
};
/**
* Convert a (radius, angle) coord to (x, y) point
*/
Polar.prototype.coordToPoint = function (coord, out) {
out = out || [];
var radius = coord[0];
var radian = coord[1] / 180 * Math.PI;
out[0] = Math.cos(radian) * radius + this.cx;
// Inverse the y
out[1] = -Math.sin(radian) * radius + this.cy;
return out;
};
/**
* Get ring area of cartesian.
* Area will have a contain function to determine if a point is in the coordinate system.
*/
Polar.prototype.getArea = function () {
var angleAxis = this.getAngleAxis();
var radiusAxis = this.getRadiusAxis();
var radiusExtent = radiusAxis.getExtent().slice();
radiusExtent[0] > radiusExtent[1] && radiusExtent.reverse();
var angleExtent = angleAxis.getExtent();
var RADIAN = Math.PI / 180;
var EPSILON = 1e-4;
return {
cx: this.cx,
cy: this.cy,
r0: radiusExtent[0],
r: radiusExtent[1],
startAngle: -angleExtent[0] * RADIAN,
endAngle: -angleExtent[1] * RADIAN,
clockwise: angleAxis.inverse,
contain: function (x, y) {
// It's a ring shape.
// Start angle and end angle don't matter
var dx = x - this.cx;
var dy = y - this.cy;
var d2 = dx * dx + dy * dy;
var r = this.r;
var r0 = this.r0;
// minus a tiny value 1e-4 in double side to avoid being clipped unexpectedly
// r == r0 contain nothing
return r !== r0 && d2 - EPSILON <= r * r && d2 + EPSILON >= r0 * r0;
},
// As the bounding box
x: this.cx - radiusExtent[1],
y: this.cy - radiusExtent[1],
width: radiusExtent[1] * 2,
height: radiusExtent[1] * 2
};
};
Polar.prototype.convertToPixel = function (ecModel, finder, value) {
var coordSys = getCoordSys(finder);
return coordSys === this ? this.dataToPoint(value) : null;
};
Polar.prototype.convertFromPixel = function (ecModel, finder, pixel) {
var coordSys = getCoordSys(finder);
return coordSys === this ? this.pointToData(pixel) : null;
};
return Polar;
}();
function getCoordSys(finder) {
var seriesModel = finder.seriesModel;
var polarModel = finder.polarModel;
return polarModel && polarModel.coordinateSystem || seriesModel && seriesModel.coordinateSystem;
}
export default Polar;
+75
View File
@@ -0,0 +1,75 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import ComponentModel from '../../model/Component.js';
export var COORD_SYS_TYPE_POLAR = 'polar';
export var COMPONENT_TYPE_POLAR = COORD_SYS_TYPE_POLAR;
var PolarModel = /** @class */function (_super) {
__extends(PolarModel, _super);
function PolarModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = PolarModel.type;
return _this;
}
PolarModel.prototype.findAxisModel = function (axisType) {
var foundAxisModel;
var ecModel = this.ecModel;
ecModel.eachComponent(axisType, function (axisModel) {
if (axisModel.getCoordSysModel() === this) {
foundAxisModel = axisModel;
}
}, this);
return foundAxisModel;
};
PolarModel.type = COORD_SYS_TYPE_POLAR;
PolarModel.dependencies = ['radiusAxis', 'angleAxis'];
PolarModel.defaultOption = {
// zlevel: 0,
z: 0,
center: ['50%', '50%'],
radius: '80%'
};
return PolarModel;
}(ComponentModel);
export default PolarModel;
+58
View File
@@ -0,0 +1,58 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import Axis from '../Axis.js';
var RadiusAxis = /** @class */function (_super) {
__extends(RadiusAxis, _super);
function RadiusAxis(scale, radiusExtent) {
return _super.call(this, 'radius', scale, radiusExtent) || this;
}
RadiusAxis.prototype.pointToData = function (point, clamp) {
return this.polar.pointToData(point, clamp)[this.dim === 'radius' ? 0 : 1];
};
return RadiusAxis;
}(Axis);
RadiusAxis.prototype.dataToRadius = Axis.prototype.dataToCoord;
RadiusAxis.prototype.radiusToData = Axis.prototype.coordToData;
export default RadiusAxis;
+153
View File
@@ -0,0 +1,153 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import Polar, { polarDimensions } from './Polar.js';
import { parsePercent } from '../../util/number.js';
import { createScaleByModel, determineAxisType, isAxisOnBand } from '../../coord/axisHelper.js';
import { COMPONENT_TYPE_POLAR, COORD_SYS_TYPE_POLAR } from './PolarModel.js';
import { SINGLE_REFERRING } from '../../util/model.js';
import { createBoxLayoutReference } from '../../util/layout.js';
import { scaleCalcNice } from '../axisNiceTicks.js';
import { AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE, scaleRawExtentInfoCreate } from '../scaleRawExtentInfo.js';
import { associateSeriesWithAxis } from '../axisStatistics.js';
/**
* Resize method bound to the polar
*/
function resizePolar(polar, polarModel, api) {
var center = polarModel.get('center');
var refContainer = createBoxLayoutReference(polarModel, api).refContainer;
polar.cx = parsePercent(center[0], refContainer.width) + refContainer.x;
polar.cy = parsePercent(center[1], refContainer.height) + refContainer.y;
var radiusAxis = polar.getRadiusAxis();
var size = Math.min(refContainer.width, refContainer.height) / 2;
var radius = polarModel.get('radius');
if (radius == null) {
radius = [0, '100%'];
} else if (!zrUtil.isArray(radius)) {
// r0 = 0
radius = [0, radius];
}
var parsedRadius = [parsePercent(radius[0], size), parsePercent(radius[1], size)];
radiusAxis.inverse ? radiusAxis.setExtent(parsedRadius[1], parsedRadius[0]) : radiusAxis.setExtent(parsedRadius[0], parsedRadius[1]);
}
/**
* Update polar
*/
function updatePolarScale(ecModel, api) {
var polar = this;
var angleAxis = polar.getAngleAxis();
var radiusAxis = polar.getRadiusAxis();
scaleRawExtentInfoCreate(angleAxis, AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE);
scaleRawExtentInfoCreate(radiusAxis, AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE);
scaleCalcNice(angleAxis);
scaleCalcNice(radiusAxis);
// Fix extent of category angle axis
if (angleAxis.type === 'category' && !angleAxis.onBand) {
var extent = angleAxis.getExtent();
var diff = 360 / angleAxis.scale.count();
angleAxis.inverse ? extent[1] += diff : extent[1] -= diff;
angleAxis.setExtent(extent[0], extent[1]);
}
}
function isAngleAxisModel(axisModel) {
return axisModel.mainType === 'angleAxis';
}
/**
* Set common axis properties
*/
function setAxis(axis, axisModel) {
var _a;
axis.type = determineAxisType(axisModel);
axis.scale = createScaleByModel(axisModel, axis.type, false);
axis.onBand = isAxisOnBand(axis.scale, axisModel);
axis.inverse = axisModel.get('inverse');
if (isAngleAxisModel(axisModel)) {
axis.inverse = axis.inverse !== axisModel.get('clockwise');
var startAngle = axisModel.get('startAngle');
var endAngle = (_a = axisModel.get('endAngle')) !== null && _a !== void 0 ? _a : startAngle + (axis.inverse ? -360 : 360);
axis.setExtent(startAngle, endAngle);
}
// Inject axis instance
axisModel.axis = axis;
axis.model = axisModel;
}
var polarCreator = {
dimensions: polarDimensions,
create: function (ecModel, api) {
var polarList = [];
ecModel.eachComponent(COMPONENT_TYPE_POLAR, function (polarModel, idx) {
var polar = new Polar(idx + '');
// Inject resize and update method
polar.update = updatePolarScale;
var radiusAxis = polar.getRadiusAxis();
var angleAxis = polar.getAngleAxis();
var radiusAxisModel = polarModel.findAxisModel('radiusAxis');
var angleAxisModel = polarModel.findAxisModel('angleAxis');
setAxis(radiusAxis, radiusAxisModel);
setAxis(angleAxis, angleAxisModel);
resizePolar(polar, polarModel, api);
polarList.push(polar);
polarModel.coordinateSystem = polar;
polar.model = polarModel;
});
// Inject coordinateSystem to series
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.get('coordinateSystem') === COORD_SYS_TYPE_POLAR) {
var polarModel = seriesModel.getReferringComponents(COMPONENT_TYPE_POLAR, SINGLE_REFERRING).models[0];
if (process.env.NODE_ENV !== 'production') {
if (!polarModel) {
throw new Error('Polar "' + zrUtil.retrieve(seriesModel.get('polarIndex'), seriesModel.get('polarId'), 0) + '" not found');
}
}
var polar = seriesModel.coordinateSystem = polarModel.coordinateSystem;
if (polar) {
associateSeriesWithAxis(polar.getRadiusAxis(), seriesModel, COORD_SYS_TYPE_POLAR);
associateSeriesWithAxis(polar.getAngleAxis(), seriesModel, COORD_SYS_TYPE_POLAR);
}
}
});
return polarList;
}
};
export default polarCreator;
+87
View File
@@ -0,0 +1,87 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
import { calcBandWidth } from '../axisBand.js';
// import AngleAxis from './AngleAxis.js';
function dataToCoordSize(dataSize, dataItem) {
// dataItem is necessary in log axis.
dataItem = dataItem || [0, 0];
return zrUtil.map(['Radius', 'Angle'], function (dim, dimIdx) {
var getterName = 'get' + dim + 'Axis';
// TODO: TYPE Check Angle Axis
var axis = this[getterName]();
var val = dataItem[dimIdx];
var halfSize = dataSize[dimIdx] / 2;
var result = axis.type === 'category' ? calcBandWidth(axis).w : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));
if (dim === 'Angle') {
result = result * Math.PI / 180;
}
return result;
}, this);
}
export default function polarPrepareCustom(coordSys) {
var radiusAxis = coordSys.getRadiusAxis();
var angleAxis = coordSys.getAngleAxis();
var radius = radiusAxis.getExtent();
radius[0] > radius[1] && radius.reverse();
return {
coordSys: {
type: 'polar',
cx: coordSys.cx,
cy: coordSys.cy,
r: radius[1],
r0: radius[0]
},
api: {
coord: function (data) {
var radius = radiusAxis.dataToRadius(data[0]);
var angle = angleAxis.dataToAngle(data[1]);
var coord = coordSys.coordToPoint([radius, angle]);
coord.push(radius, angle * Math.PI / 180);
return coord;
},
size: zrUtil.bind(dataToCoordSize, coordSys)
}
};
}
+57
View File
@@ -0,0 +1,57 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import Axis from '../Axis.js';
var IndicatorAxis = /** @class */function (_super) {
__extends(IndicatorAxis, _super);
function IndicatorAxis(dim, scale, radiusExtent) {
var _this = _super.call(this, dim, scale, radiusExtent) || this;
_this.type = 'value';
_this.angle = 0;
_this.name = '';
return _this;
}
return IndicatorAxis;
}(Axis);
export default IndicatorAxis;
+193
View File
@@ -0,0 +1,193 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 IndicatorAxis from './IndicatorAxis.js';
import IntervalScale from '../../scale/Interval.js';
import * as numberUtil from '../../util/number.js';
import { COMPONENT_TYPE_RADAR, COORD_SYS_TYPE_RADAR, RADAR_DEFAULT_SPLIT_NUMBER, SERIES_TYPE_RADAR } from './RadarModel.js';
import { map, each, isString, isNumber } from 'zrender/lib/core/util.js';
import { scaleCalcAlign } from '../axisAlignTicks.js';
import { createBoxLayoutReference } from '../../util/layout.js';
import { AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE, scaleRawExtentInfoCreate } from '../scaleRawExtentInfo.js';
import { ensureValidSplitNumber } from '../../scale/helper.js';
import { associateSeriesWithAxis } from '../axisStatistics.js';
var Radar = /** @class */function () {
function Radar(radarModel, ecModel, api) {
this.type = COORD_SYS_TYPE_RADAR;
/**
*
* Radar dimensions
*/
this.dimensions = [];
this._model = radarModel;
this._indicatorAxes = map(radarModel.getIndicatorModels(), function (indicatorModel, idx) {
var dim = 'indicator_' + idx;
var indicatorAxis = new IndicatorAxis(dim, new IntervalScale()
// (indicatorModel.get('axisType') === 'log') ? new LogScale() : new IntervalScale()
);
indicatorAxis.name = indicatorModel.get('name');
// Inject model and axis
indicatorAxis.model = indicatorModel;
indicatorModel.axis = indicatorAxis;
this.dimensions.push(dim);
return indicatorAxis;
}, this);
this.resize(radarModel, api);
}
Radar.prototype.getIndicatorAxes = function () {
return this._indicatorAxes;
};
Radar.prototype.dataToPoint = function (value, indicatorIndex) {
var indicatorAxis = this._indicatorAxes[indicatorIndex];
return this.coordToPoint(indicatorAxis.dataToCoord(value), indicatorIndex);
};
// TODO: API should be coordToPoint([coord, indicatorIndex])
Radar.prototype.coordToPoint = function (coord, indicatorIndex) {
var indicatorAxis = this._indicatorAxes[indicatorIndex];
var angle = indicatorAxis.angle;
var x = this.cx + coord * Math.cos(angle);
var y = this.cy - coord * Math.sin(angle);
return [x, y];
};
Radar.prototype.pointToData = function (pt) {
var dx = pt[0] - this.cx;
var dy = pt[1] - this.cy;
var radius = Math.sqrt(dx * dx + dy * dy);
dx /= radius;
dy /= radius;
var radian = Math.atan2(-dy, dx);
// Find the closest angle
// FIXME index can calculated directly
var minRadianDiff = Infinity;
var closestAxis;
var closestAxisIdx = -1;
for (var i = 0; i < this._indicatorAxes.length; i++) {
var indicatorAxis = this._indicatorAxes[i];
var diff = Math.abs(radian - indicatorAxis.angle);
if (diff < minRadianDiff) {
closestAxis = indicatorAxis;
closestAxisIdx = i;
minRadianDiff = diff;
}
}
return [closestAxisIdx, +(closestAxis && closestAxis.coordToData(radius))];
};
Radar.prototype.resize = function (radarModel, api) {
var refContainer = createBoxLayoutReference(radarModel, api).refContainer;
var center = radarModel.get('center');
var clockwise = radarModel.get('clockwise') || false;
var viewSize = Math.min(refContainer.width, refContainer.height) / 2;
this.cx = numberUtil.parsePercent(center[0], refContainer.width) + refContainer.x;
this.cy = numberUtil.parsePercent(center[1], refContainer.height) + refContainer.y;
this.startAngle = radarModel.get('startAngle') * Math.PI / 180;
// radius may be single value like `20`, `'80%'`, or array like `[10, '80%']`
var radius = radarModel.get('radius');
if (isString(radius) || isNumber(radius)) {
radius = [0, radius];
}
this.r0 = numberUtil.parsePercent(radius[0], viewSize);
this.r = numberUtil.parsePercent(radius[1], viewSize);
var sign = clockwise ? -1 : 1;
each(this._indicatorAxes, function (indicatorAxis, idx) {
indicatorAxis.setExtent(this.r0, this.r);
var angle = this.startAngle + sign * idx * Math.PI * 2 / this._indicatorAxes.length;
// Normalize to [-PI, PI]
angle = Math.atan2(Math.sin(angle), Math.cos(angle));
indicatorAxis.angle = angle;
}, this);
};
Radar.prototype.update = function (ecModel, api) {
var indicatorAxes = this._indicatorAxes;
var radarModel = this._model;
var splitNumber = ensureValidSplitNumber(radarModel.get('splitNumber'), RADAR_DEFAULT_SPLIT_NUMBER);
var dummyScale = new IntervalScale();
dummyScale.setExtent(0, splitNumber);
dummyScale.setConfig({
interval: 1
});
// Force all the axis fixing the maxSplitNumber.
each(indicatorAxes, function (indicatorAxis) {
scaleRawExtentInfoCreate(indicatorAxis, AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE);
scaleCalcAlign(indicatorAxis, dummyScale);
});
};
Radar.prototype.convertToPixel = function (ecModel, finder, value) {
console.warn('Not implemented.');
return null;
};
Radar.prototype.convertFromPixel = function (ecModel, finder, pixel) {
console.warn('Not implemented.');
return null;
};
Radar.prototype.containPoint = function (point) {
console.warn('Not implemented.');
return false;
};
Radar.create = function (ecModel, api) {
var radarList = [];
ecModel.eachComponent(COMPONENT_TYPE_RADAR, function (radarModel) {
var radar = new Radar(radarModel, ecModel, api);
radarList.push(radar);
radarModel.coordinateSystem = radar;
});
ecModel.eachSeriesByType(SERIES_TYPE_RADAR, function (radarSeries) {
if (radarSeries.get('coordinateSystem') === COORD_SYS_TYPE_RADAR) {
// Inject coordinate system
// @ts-ignore
var radar = radarSeries.coordinateSystem = radarList[radarSeries.get('radarIndex') || 0];
if (radar) {
each(radar.getIndicatorAxes(), function (indicatorAxis) {
associateSeriesWithAxis(indicatorAxis, radarSeries, COORD_SYS_TYPE_RADAR);
});
}
}
});
return radarList;
};
/**
* Radar dimensions is based on the data
*/
Radar.dimensions = [];
return Radar;
}();
export default Radar;
+171
View File
@@ -0,0 +1,171 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import * as zrUtil from 'zrender/lib/core/util.js';
import axisDefault from '../axisDefault.js';
import Model from '../../model/Model.js';
import { AxisModelCommonMixin } from '../axisModelCommonMixin.js';
import ComponentModel from '../../model/Component.js';
import tokens from '../../visual/tokens.js';
import { getUID } from '../../util/component.js';
var valueAxisDefault = axisDefault.value;
export var COORD_SYS_TYPE_RADAR = 'radar';
export var COMPONENT_TYPE_RADAR = COORD_SYS_TYPE_RADAR;
export var SERIES_TYPE_RADAR = COORD_SYS_TYPE_RADAR;
export var RADAR_DEFAULT_SPLIT_NUMBER = 5;
function defaultsShow(opt, show) {
return zrUtil.defaults({
show: show
}, opt);
}
var RadarModel = /** @class */function (_super) {
__extends(RadarModel, _super);
function RadarModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = RadarModel.type;
return _this;
}
RadarModel.prototype.optionUpdated = function () {
var boundaryGap = this.get('boundaryGap');
var splitNumber = this.get('splitNumber');
var clockwise = this.get('clockwise');
var scale = this.get('scale');
var axisLine = this.get('axisLine');
var axisTick = this.get('axisTick');
// let axisType = this.get('axisType');
var axisLabel = this.get('axisLabel');
var nameTextStyle = this.get('axisName');
var showName = this.get(['axisName', 'show']);
var nameFormatter = this.get(['axisName', 'formatter']);
var nameGap = this.get('axisNameGap');
var triggerEvent = this.get('triggerEvent');
var indicatorModels = zrUtil.map(this.get('indicator') || [], function (indicatorOpt) {
// PENDING
if (indicatorOpt.max != null && indicatorOpt.max > 0 && !indicatorOpt.min) {
indicatorOpt.min = 0;
} else if (indicatorOpt.min != null && indicatorOpt.min < 0 && !indicatorOpt.max) {
indicatorOpt.max = 0;
}
var iNameTextStyle = nameTextStyle;
if (indicatorOpt.color != null) {
iNameTextStyle = zrUtil.defaults({
color: indicatorOpt.color
}, nameTextStyle);
}
// Use same configuration
var innerIndicatorOpt = zrUtil.merge(zrUtil.clone(indicatorOpt), {
boundaryGap: boundaryGap,
splitNumber: splitNumber,
clockwise: clockwise,
scale: scale,
axisLine: axisLine,
axisTick: axisTick,
// axisType: axisType,
axisLabel: axisLabel,
// Compatible with 2 and use text
name: indicatorOpt.text,
showName: showName,
nameLocation: 'end',
nameGap: nameGap,
// min: 0,
nameTextStyle: iNameTextStyle,
triggerEvent: triggerEvent
}, false);
if (zrUtil.isString(nameFormatter)) {
var indName = innerIndicatorOpt.name;
innerIndicatorOpt.name = nameFormatter.replace('{value}', indName != null ? indName : '');
} else if (zrUtil.isFunction(nameFormatter)) {
innerIndicatorOpt.name = nameFormatter(innerIndicatorOpt.name, innerIndicatorOpt);
}
var model = new Model(innerIndicatorOpt, null, this.ecModel);
zrUtil.mixin(model, AxisModelCommonMixin.prototype);
// For triggerEvent.
model.mainType = 'radar';
model.componentIndex = this.componentIndex;
// FIXME: construct an AxisBaseModel directly, rather than mixin.
// @ts-ignore
model.uid = getUID('ec_radar');
return model;
}, this);
this._indicatorModels = indicatorModels;
};
RadarModel.prototype.getIndicatorModels = function () {
return this._indicatorModels;
};
RadarModel.type = COMPONENT_TYPE_RADAR;
RadarModel.defaultOption = {
// zlevel: 0,
z: 0,
center: ['50%', '50%'],
radius: '50%',
startAngle: 90,
clockwise: false,
axisName: {
show: true,
color: tokens.color.axisLabel
// formatter: null
// textStyle: {}
},
boundaryGap: [0, 0],
splitNumber: RADAR_DEFAULT_SPLIT_NUMBER,
axisNameGap: 15,
scale: false,
// Polygon or circle
shape: 'polygon',
axisLine: zrUtil.merge({
lineStyle: {
color: tokens.color.neutral20
}
}, valueAxisDefault.axisLine),
axisLabel: defaultsShow(valueAxisDefault.axisLabel, false),
axisTick: defaultsShow(valueAxisDefault.axisTick, false),
// axisType: 'value',
splitLine: defaultsShow(valueAxisDefault.splitLine, true),
splitArea: defaultsShow(valueAxisDefault.splitArea, true),
// {text, min, max}
indicator: []
};
return RadarModel;
}(ComponentModel);
export default RadarModel;
+581
View File
@@ -0,0 +1,581 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { assert, isArray, eqNaN, isFunction, each, createHashMap } from 'zrender/lib/core/util.js';
import { parsePercent } from 'zrender/lib/contain/text.js';
import { isIntervalScale, isLogScale, isOrdinalScale, isTimeScale } from '../scale/helper.js';
import { makeInner, initExtentForUnion, unionExtentFromNumber, isValidNumberForExtent, extentHasValue, unionExtentFromExtent, unionExtentStartFromNumber, unionExtentEndFromNumber, ensureExtentAscSimply } from '../util/model.js';
import { discourageOnAxisZero, getDataDimensionsOnAxis, isAxisOnBand } from './axisHelper.js';
import { getCoordForCoordSysUsageKindBox } from '../core/CoordinateSystem.js';
import { error } from '../util/log.js';
import { isNullableNumberFinite, mathMax, mathMin } from '../util/number.js';
import { SCALE_EXTENT_KIND_MAPPING } from '../scale/scaleMapper.js';
import { eachKeyOnAxis, eachSeriesOnAxis } from './axisStatistics.js';
/**
* NOTICE: Can be only used in `ensureScaleStore(axisLike)`.
*
* In most cases the instances of `Axis` and `Scale` are one-to-one mapping and share the same lifecycle.
* But in some external usage (such as echarts-gl), axis instance does not necessarily exist, and only
* scale instance and axisModel are used. Therefore we store the internal info on scale instance directly.
*/
var scaleInner = makeInner();
export var AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE = 1;
export var AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM = 2;
var AXIS_EXTENT_INFO_BUILD_FROM_EMPTY = 3;
var ScaleRawExtentInfo = /** @class */function () {
function ScaleRawExtentInfo(scale, model,
// Typically: data extent from all series on this axis.
dataExtent, requireStartValue, requireContainShape) {
var isOrdinal = isOrdinalScale(scale);
var axisDataLen = isOrdinal
// FIXME: there is a flaw here: if there is no "block" data processor like `dataZoom`,
// and progressive rendering is using, here the category result might just only contain
// the processed chunk rather than the entire result.
? model.getCategories().length : null;
// [CATEGORY_AXIS_MODEL_DATA_IS_EMPTY_ARRAY]:
// This is only for backward compatibility - `xxxAxis: {data: []}` can declare this axis as
// a "category" axis and use `series.data` to determine its extent but the axis is blank - only
// axis line is displayed. This is a conincidence, but it is used in some cases.
var categoryAxisModelDataIsEmptyArray;
if (isOrdinal) {
var axisModelDataArray = model.getCategories(true);
categoryAxisModelDataIsEmptyArray = axisModelDataArray && !axisModelDataArray.length;
}
// NOTE: also considered the input dataExtent may be still in the initialized state `[Infinity, -Infinity]`.
var dataMM = dataExtent.slice();
// custom dataMin/dataMax.
// Also considered `modelDataMinMax[0] > modelDataMinMax[1]` may occur.
if (isIntervalScale(scale) || isLogScale(scale) || isTimeScale(scale)) {
unionExtentStartFromNumber(dataMM, parseAxisModelMinMax(scale, model.get('dataMin', true)));
unionExtentEndFromNumber(dataMM, parseAxisModelMinMax(scale, model.get('dataMax', true)));
}
if (!extentHasValue(dataMM)) {
// dataMM may be still `[Infinity, -Infinity]`, we use `NaN` on the subsequent calculations
// to force the `noZoomEffMM` to be `[NaN, NaN]` if needed.
dataMM[0] = dataMM[1] = NaN;
}
var noZoomEffMM = [];
var fixMM = [false, false];
// Notice: When min/max is not set (that is, when there are null/undefined,
// which is the most common case), these cases should be ensured:
// (1) For 'ordinal', show all axis.data.
// (2) For others:
// + `boundaryGap` is applied (if min/max set, boundaryGap is
// disabled).
// + If `needIncludeZero`, min/max should be zero, otherwise, min/max should
// be the result that originalExtent enlarged by boundaryGap.
// (3) If no data, it should be ensured that `scale.setBlank` is set.
var modelMinRaw = model.get('min', true);
if (modelMinRaw === 'dataMin') {
noZoomEffMM[0] = dataMM[0];
fixMM[0] = true;
} else {
noZoomEffMM[0] = parseAxisModelMinMax(scale, isFunction(modelMinRaw)
// This callback always provides users the full data extent (before data is filtered).
? modelMinRaw({
min: dataMM[0],
max: dataMM[1]
}) : modelMinRaw);
// If `xxxAxis.min: null/undefined`, min should not be fixed.
fixMM[0] = noZoomEffMM[0] != null;
}
var modelMaxRaw = model.get('max', true);
if (modelMaxRaw === 'dataMax') {
noZoomEffMM[1] = dataMM[1];
fixMM[1] = true;
} else {
noZoomEffMM[1] = parseAxisModelMinMax(scale, isFunction(modelMaxRaw)
// This callback always provides users the full data extent (before data is filtered).
? modelMaxRaw({
min: dataMM[0],
max: dataMM[1]
}) : modelMaxRaw);
// If `xxxAxis.max: null/undefined`, max should not be fixed.
fixMM[1] = noZoomEffMM[1] != null;
}
var boundaryGap = parseBoundaryGapOption(scale, model);
var span = !isOrdinal
// PENDING: Historicall behavior but may not reasonable enough.
? dataMM[1] - dataMM[0] || Math.abs(dataMM[0]) : null;
// NOTE: If a numeric axis min/max is specified as 'dataMin'/'dataMax',
// `boundaryGap` will not be used.
if (noZoomEffMM[0] == null) {
noZoomEffMM[0] = isOrdinal ? categoryAxisModelDataIsEmptyArray ? dataMM[0] : axisDataLen ? 0 : NaN : dataMM[0] - boundaryGap[0] * span;
}
if (noZoomEffMM[1] == null) {
noZoomEffMM[1] = isOrdinal ? categoryAxisModelDataIsEmptyArray ? dataMM[1] : axisDataLen ? axisDataLen - 1 : NaN : dataMM[1] + boundaryGap[1] * span;
}
// Normalize to `NaN` if invalid; e.g., this may occur when `dataMM` has Infinity.
!isValidNumberForExtent(noZoomEffMM[0]) && (noZoomEffMM[0] = NaN);
!isValidNumberForExtent(noZoomEffMM[1]) && (noZoomEffMM[1] = NaN);
var isBlank = categoryAxisModelDataIsEmptyArray || eqNaN(noZoomEffMM[0]) || eqNaN(noZoomEffMM[1]) || isOrdinal && !axisDataLen;
// NOTE: `needIncludeZero` is not applicable to LogScale, TimeScale, OrdinalScale.
var needIncludeZeroApplicable = isIntervalScale(scale);
var needIncludeZero = needIncludeZeroApplicable && model.needIncludeZero && model.needIncludeZero();
if (needIncludeZero) {
if (noZoomEffMM[0] > 0 && noZoomEffMM[1] > 0 && !fixMM[0]) {
noZoomEffMM[0] = 0;
// fixMM[0] = true;
}
if (noZoomEffMM[0] < 0 && noZoomEffMM[1] < 0 && !fixMM[1]) {
noZoomEffMM[1] = 0;
// fixMM[1] = true;
}
}
var needToggleAxisInverse = false;
if (noZoomEffMM[0] > noZoomEffMM[1]) {
// Historically, if users set `xxxAxis.min > xxxAxis.max`, or `xxxAxis.max < dataExtent[0]`,
// or `xxxAxis.min > dataExtent[1]` the behavior is sometimes like `xxxAxis.inverse = true`,
// sometimes abnormal. We remain backward compatible with the former one, though this feature
// may not be reasonable.
// And handle it after "needIncludeZero" is also for backward compatibility.
noZoomEffMM.reverse();
needToggleAxisInverse = true;
}
var startValue = parseAxisModelMinMax(scale, model.get('startValue', true));
var startValueSpecified = startValue != null;
if (!isNullableNumberFinite(startValue) && requireStartValue) {
startValue = scale.getDefaultStartValue ? scale.getDefaultStartValue() : 0;
}
if (isNullableNumberFinite(startValue)
// Keep backward compatibility and enable `xxxAxis.scale: true` enabled on bar series:
// if `xxxAxis.scale: true` and `startValue` is not specified, do not union the default `startValue`,
&& (startValueSpecified || !needIncludeZeroApplicable || needIncludeZero)) {
if (startValue < noZoomEffMM[0] && !fixMM[0]) {
noZoomEffMM[0] = startValue;
fixMM[0] = true;
} else if (startValue > noZoomEffMM[1] && !fixMM[1]) {
noZoomEffMM[1] = startValue;
fixMM[1] = true;
}
}
var internal = this._i = {
scale: scale,
dataMM: dataMM,
noZoomEffMM: noZoomEffMM,
zoomMM: [],
fixMM: fixMM,
zoomFixMM: [false, false],
startValue: startValue,
isBlank: isBlank,
incl0: needIncludeZero,
tggAxInv: needToggleAxisInverse,
ctnShp: requireContainShape
};
sanitizeExtent(internal, noZoomEffMM);
}
ScaleRawExtentInfo.prototype.makeNoZoom = function () {
return this._i.noZoomEffMM.slice();
};
ScaleRawExtentInfo.prototype.makeFinal = function () {
var internal = this._i;
var zoomMM = internal.zoomMM;
var noZoomEffMM = internal.noZoomEffMM;
var zoomFixMM = internal.zoomFixMM;
var fixMM = internal.fixMM;
var result = {
fixMM: fixMM,
zoomFixMM: zoomFixMM,
isBlank: internal.isBlank,
incl0: internal.incl0,
tggAxInv: internal.tggAxInv,
ctnShp: internal.ctnShp,
effMM: noZoomEffMM.slice()
};
var effMM = result.effMM;
// NOTE: Switching `fixMM` probably leads to abrupt extent changes when draging a `dataZoom`
// handle, since `fixMM` impact the "nice extent" and "nice ticks" calculation.
// Consider a case:
// dataZoom `start` is 2% but its `end` is 100%, (or vice versa), we currently only set `fixMM[0]`
// as `true` but remain `fixMM[1]` as `false` for this case to avoid unnecessary abrupt change.
// Incidentally, the effect is not unacceptable if we set both `fixMM[0]/[1]` as `true`.
if (zoomMM[0] != null) {
effMM[0] = zoomMM[0];
fixMM[0] = zoomFixMM[0] = true;
}
if (zoomMM[1] != null) {
effMM[1] = zoomMM[1];
fixMM[1] = zoomFixMM[1] = true;
}
sanitizeExtent(internal, effMM);
return result;
};
ScaleRawExtentInfo.prototype.makeRenderInfo = function () {
return {
startValue: this._i.startValue
};
};
/**
* NOTICE:
* - Do not set them if the percent are 0% or 100%. (See `AxisProxy['reset']`.)
* - The caller must ensure `start <= end` and the range is equal or less then `noZoomEffMM`.
* (See `AxisProxy['calculateDataWindow']`.)
* - The outcome `_zoomMM` may have both `NullUndefined` and a finite value, like `[undefined, 123]`.
*/
ScaleRawExtentInfo.prototype.setZoomMM = function (idxMinMax, val) {
this._i.zoomMM[idxMinMax] = val;
};
return ScaleRawExtentInfo;
}();
export { ScaleRawExtentInfo };
/**
* Should be called when a new extent is created or modified.
*/
function sanitizeExtent(internal, mm) {
var scale = internal.scale;
var dataMM = internal.dataMM;
if (scale.sanitize) {
mm[0] = scale.sanitize(mm[0], dataMM);
mm[1] = scale.sanitize(mm[1], dataMM);
ensureExtentAscSimply(mm);
}
}
function parseAxisModelMinMax(scale, minMax) {
return minMax == null ? null // null/undefined means not specified and other default values can be applied.
: eqNaN(minMax) ? NaN // NaN means a deliberate invalid number.
: scale.parse(minMax);
}
function parseBoundaryGapOption(scale, model) {
var boundaryGapOptionArr;
if (isOrdinalScale(scale)) {
boundaryGapOptionArr = [0, 0];
} else {
var boundaryGap = model.get('boundaryGap');
if (typeof boundaryGap === 'boolean') {
if (process.env.NODE_ENV !== 'production') {
if (boundaryGap === true) {
console.warn('Boolean type for boundaryGap is only ' + 'allowed for ordinal axis. Please use string in ' + 'percentage instead, e.g., "20%". Currently, ' + 'boundaryGap is set to 0.');
}
}
boundaryGap = null;
}
boundaryGapOptionArr = isArray(boundaryGap) ? boundaryGap : [boundaryGap, boundaryGap];
}
return [parseBoundaryGapOptionItem(boundaryGapOptionArr[0]), parseBoundaryGapOptionItem(boundaryGapOptionArr[1])];
}
function parseBoundaryGapOptionItem(opt) {
return parsePercent(typeof opt === 'boolean' ? 0 : opt, 1) || 0;
}
/**
* NOTE: `associateSeriesWithAxis` is not necessarily called, e.g., when
* an axis is not used by any series.
*/
function ensureScaleStore(axisLike) {
var store = scaleInner(axisLike.scale);
if (!store.extent) {
store.extent = initExtentForUnion();
}
return store;
}
/**
* This supports union extent on case like: pie (or other similar series)
* lays out on cartesian2d.
* @see scaleRawExtentInfoCreate
*/
export function scaleRawExtentInfoEnableBoxCoordSysUsage(axisLike, coordSysDimIdxMap) {
ensureScaleStore(axisLike).dimIdxInCoord = coordSysDimIdxMap.get(axisLike.dim);
}
/**
* @usage
* class SomeCoordSys {
* static create() {
* ecModel.eachSeries(function (seriesModel) {
* associateSeriesWithAxis(axis1, seriesModel, ...);
* associateSeriesWithAxis(axis2, seriesModel, ...);
* // ...
* });
* }
* update() {
* scaleRawExtentInfoCreate(axis1);
* scaleRawExtentInfoCreate(axis2);
* }
* }
* class AxisProxy {
* reset() {
* scaleRawExtentInfoCreate(axis1);
* }
* }
*
* NOTICE:
* - `associateSeriesWithAxis`(in `axisStatistics.ts`) should be called in:
* - Coord sys create method.
* - `scaleRawExtentInfoCreate` should be typically called in:
* - `dataZoom` processor. It requires processing like:
* 1. Filter series data by dataZoom1;
* 2. Union the filtered data and init the extent of the orthogonal axes, which is the 100% of dataZoom2;
* 3. Filter series data by dataZoom2;
* 4. ...
* - Coord sys update method, for other axes that not covered by `dataZoom`.
* NOTE: If a `dataZoom` covers this series, this data and its extent has been dataZoom-filtered.
* Therefore this handling should not before `dataZoom`.
* - The callback of `min`/`max` in ec option should NOT be called multiple times,
* therefore, we initialize `ScaleRawExtentInfo` uniformly in `scaleRawExtentInfoCreate`.
*
* @see SCALE_EXTENT_CONSTRUCTION for the full processing flow.
*/
export function scaleRawExtentInfoCreate(axis, from) {
var scale = axis.scale;
var model = axis.model;
var axisDim = axis.dim;
if (process.env.NODE_ENV !== 'production') {
assert(scale && model && axisDim);
}
if (scale.rawExtentInfo) {
if (process.env.NODE_ENV !== 'production') {
// Check for incorrect impl - the duplicated calling of this method is only allowed in
// these cases:
// - First in `AxisProxy['reset']` (for dataZoom)
// - Then in `CoordinateSystem['update']`.
// - Then after `chart.appendData()` due to `dirtyOnOverallProgress: true`
assert(scale.rawExtentInfo.from !== from || from === AXIS_EXTENT_INFO_BUILD_FROM_DATA_ZOOM);
}
return;
}
scaleRawExtentInfoCreateDeal(scale, axis, axisDim, model, from);
}
function scaleRawExtentInfoCreateDeal(scale, axis, axisDim, model, from) {
var scaleStore = ensureScaleStore(axis);
var extent = scaleStore.extent;
var requireStartValue = false;
eachSeriesOnAxis(axis, function (seriesModel) {
if (seriesModel.boxCoordinateSystem) {
// This supports union extent on case like: pie (or other similar series)
// lays out on cartesian2d.
var coord = getCoordForCoordSysUsageKindBox(seriesModel).coord;
var dimIdx = scaleStore.dimIdxInCoord;
if (!(dimIdx >= 0)) {
if (process.env.NODE_ENV !== 'production') {
// Require `scaleRawExtentInfoEnableBoxCoordSysUsage` have been called to support it.
// But if users set it, give a error log but no exceptions.
error("Property \"series.coord\" is not supported on axis " + seriesModel.boxCoordinateSystem.type + ".");
}
}
// Only `[val1, val2]` case needs to be supported currently.
else if (isArray(coord)) {
var coordItem = coord[dimIdx];
if (coordItem != null && !isArray(coordItem)) {
unionExtentFromNumber(extent, scale.parse(coordItem));
}
}
} else if (seriesModel.coordinateSystem) {
// NOTE: This data may have been filtered by dataZoom on orthogonal axes.
var data_1 = seriesModel.getData();
if (data_1) {
var filter_1 = scale.getFilter ? scale.getFilter() : null;
each(getDataDimensionsOnAxis(data_1, axisDim), function (dim) {
unionExtentFromExtent(extent, data_1.getApproximateExtent(dim, filter_1));
});
}
if (seriesModel.__requireStartValue && seriesModel.__requireStartValue(axis)) {
requireStartValue = true;
}
}
});
var requireContainShape = determineRequireContainShape(scale, axis, model);
var rawExtentInfo = new ScaleRawExtentInfo(scale, model, extent, requireStartValue, requireContainShape);
injectScaleRawExtentInfo(scale, rawExtentInfo, from);
scaleStore.extent = null; // Clean up
}
/**
* `rawExtentInfo` may not be created in some cases, such as no series declared or extra useless
* axes declared in ec option. In this case we still create a default one for that empty axis.
*/
function scaleRawExtentInfoBuildDefault(axisLike, dataExtent) {
var scale = axisLike.scale;
if (process.env.NODE_ENV !== 'production') {
assert(!scale.rawExtentInfo);
}
injectScaleRawExtentInfo(scale, new ScaleRawExtentInfo(scale, axisLike.model, dataExtent, false, false), AXIS_EXTENT_INFO_BUILD_FROM_EMPTY);
}
function injectScaleRawExtentInfo(scale, scaleRawExtentInfo, from) {
// @ts-ignore
scale.rawExtentInfo = scaleRawExtentInfo;
// @ts-ignore
scaleRawExtentInfo.from = from;
}
/**
* See `axisSnippets.ts` for some commonly used handlers.
*
* FIXME:
* `boundaryGap: true` (i.e., `onBand: true` in code) has long been supported on category axis.
* And it is implemented in different code and not merged to this implementation yet.
*/
export function registerAxisContainShapeHandler(
// `axisStatKey` is used to quickly omit irrelevant handlers,
// since handlers need to be iterated per axis.
axisStatKey, handler) {
if (process.env.NODE_ENV !== 'production') {
assert(!axisContainShapeHandlerMap.get(axisStatKey));
}
axisContainShapeHandlerMap.set(axisStatKey, handler);
}
var axisContainShapeHandlerMap = createHashMap();
/**
* Prepare axis scale extent before "nice".
* Item of returned array can only be number (including Infinity and NaN).
*/
export function adoptScaleRawExtentInfoAndPrepare(scale, model, ecModel, axis, externalDataExtent) {
if (process.env.NODE_ENV !== 'production') {
assert(!externalDataExtent || !scale.rawExtentInfo);
}
if (!scale.rawExtentInfo) {
scaleRawExtentInfoBuildDefault({
scale: scale,
model: model
}, externalDataExtent || initExtentForUnion());
}
var rawExtentResult = scale.rawExtentInfo.makeFinal();
// NOTE: This `scale.setExtent()` is required by:
// - `axisNiceTicks.ts` and `axisAlignTicks.ts`, where the internal `scaleMapper` may be required.
var effectiveMinMax = rawExtentResult.effMM;
scale.setExtent(effectiveMinMax[0], effectiveMinMax[1]);
scale.setBlank(rawExtentResult.isBlank);
if (axis && rawExtentResult.tggAxInv && ecModel && !ecModel.get('legacyMinMaxDontInverseAxis')) {
axis.inverse = !axis.inverse;
}
return rawExtentResult;
}
function determineRequireContainShape(scale, axis, model) {
var onBand = isAxisOnBand(scale, model);
var modelContainShape = model.get('containShape', true);
if (modelContainShape == null && !onBand) {
modelContainShape = true;
}
if (!modelContainShape) {
return false;
}
var requireContainShape = false;
eachKeyOnAxis(axis, function (axisStatKey) {
requireContainShape = !!axisContainShapeHandlerMap.get(axisStatKey) || requireContainShape;
});
return requireContainShape;
}
/**
* This implements ec option `someAxis.containShape`. That is, expand scale extent slightly to
* ensure shapes of specific series are fully contained in the axis extent without overflow.
*
* NOTICE:
* Scale extent (data extent) and axis pixel extent (pixel extent) and are required as inputs.
* - See BAND_WIDTH_USED_SCALE_LINEAR_SPAN.
* - Axis pixel extent has been set outside, though it may be modified later (e.g., via `outerBounds`).
*
* @tutorial [AXIS_CONTAIN_SHAPE_PROCESSING_ORDER]
* This is a trade-off between the following 2 approaches:
* - Steps: (the current implementation)
* 1. Process `dataZoom` based on a full window `noZoomEffMM`.
* 2. Perform "nice" or "align" scale, where `intervalScaleEnsureValidExtent`-ish may be performed to
* expand extent to avoid `extent[0] === extent[1]`.
* 3. Calculate linear supplement of containShape based on the final result.
* Cons:
* - Abrupt changes occur when zooming away from 0% or 100%.
* - Edge shapes are clipped in "dataZoom shadow".
* - Steps: (discarded)
* 1. Calculate linear supplement of containShape based on `noZoomEffMM` and
* `intervalScaleEnsureValidExtent`-ish.
* 2. Process `dataZoom` based on a full window `noZoomEffMM + linearSupplement`.
* 3. Perform "nice"/"align" scale.
* Cons:
* - Input `startValue: 0` (in ec option or action) does not corresponds to `0%`, which is unacceptable.
* - Not easy to perform `intervalScaleEnsureValidExtent`-ish before "nice"/"align" processing.
*
* @see SCALE_EXTENT_CONSTRUCTION for the full processing flow.
*/
export function adoptScaleExtentKindMapping(axis, scale, rawExtentResult, ecModel) {
if (!rawExtentResult.ctnShp) {
return;
}
var linearSupplement;
eachKeyOnAxis(axis, function (axisStatKey) {
var handler = axisContainShapeHandlerMap.get(axisStatKey);
if (handler) {
// This feature can be implemented by either expanding axis extent or scale extent. The choice depends
// on whether series shape sizes are defined in pixels or data space. For example, scatter series glyph
// sizes is mainly defined in pixel, while bar series `bandWidth` is mainly determined by given percents
// of data scale. Since currently scatter does not require this feature, we implement it only on the
// data scale.
var singleLinearSupplement = handler(axis, ecModel);
if (singleLinearSupplement) {
linearSupplement = linearSupplement || [0, 0];
unionExtentStartFromNumber(linearSupplement, singleLinearSupplement[0]);
unionExtentEndFromNumber(linearSupplement, singleLinearSupplement[1]);
// Consider the consistency of `onZero` behavior (not varying by series data; otherwise error-prone
// to users), if any `containShape` really performed on this axis, discourage `onZero`.
discourageOnAxisZero(axis);
}
}
});
if (!linearSupplement) {
return;
}
var scaleExtent = scale.getExtent();
if (isOrdinalScale(scale)) {
if (!axis.onBand) {
// - Zooming on `OrdinalScale` auto "snaps" to integer ticks, which causes edge shapes to
// always overlap and be clipped at the boundaries. Therefore we always supplement it with
// half bandWith to avoid that overlapping.
// - `linearSupplement` is typically [-0.5, 0.5] in this case. `linearSupplement` exists only
// if any series call `registerAxisContainShapeHandler`.
// - PENDING: For historical reason, `onBand: true` has another implementation to handle
// this case. Merge them to this?
scale.setExtent2(SCALE_EXTENT_KIND_MAPPING, mathMin(scaleExtent[0], scaleExtent[0] + linearSupplement[0]), mathMax(scaleExtent[1], scaleExtent[1] + linearSupplement[1]));
}
} else {
// For other cases, `SCALE_EXTENT_KIND_MAPPING` is only used on the full window of `dataZoom`,
// where the visual result is more intuitive when zooming: when dataZoom is applied and its ends
// (i.e., `zoomMM`) do not reach 0% or 100%, the axis ends should exactly respect to the dataZoom
// ends, and shapes are clipped if overflowing.
var scaleExtentExpanded = scaleExtent.slice();
if (!rawExtentResult.zoomFixMM[0]) {
scaleExtentExpanded[0] = mathMin(scaleExtentExpanded[0], scale.transformOut(scale.transformIn(scaleExtentExpanded[0], null) + linearSupplement[0], null));
}
if (!rawExtentResult.zoomFixMM[1]) {
scaleExtentExpanded[1] = mathMax(scaleExtentExpanded[1], scale.transformOut(scale.transformIn(scaleExtentExpanded[1], null) + linearSupplement[1], null));
}
if (scaleExtentExpanded[0] < scaleExtent[0] || scaleExtentExpanded[1] > scaleExtent[1]) {
scale.setExtent2(SCALE_EXTENT_KIND_MAPPING, scaleExtentExpanded[0], scaleExtentExpanded[1]);
}
}
// NOTE: since currently `SCALE_EXTENT_KIND_MAPPING` is never required to be displayed, we
// do not need to find a proper precision for that. But if it is required in the future, We
// can use `getAcceptableTickPrecision` to find a proper precision.
}
+117
View File
@@ -0,0 +1,117 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import ComponentModel from '../../model/Component.js';
import { AxisModelCommonMixin } from '../axisModelCommonMixin.js';
import { mixin } from 'zrender/lib/core/util.js';
// PENDING: For historical reason,
// in ec option:
// It can only declare as `series:{coordinateSystem: "singleAxis", ...}`
// rather than 'single'. Therefore every `.get('coordinateSystem')` must
// match "singleAxis". (See `referHelper.ts`)
// And the component name can only be `singleAxis: {...}`.
// But the internal convention uses 'singe' as coordinate system name
// and dimension name.
export var COORD_SYS_TYPE_SINGLE = 'single';
export var COORD_SYS_TYPE_SINGLE_AXIS_COMPATIBLE = 'singleAxis';
export var COMPONENT_TYPE_SINGLE_AXIS = 'singleAxis';
var SingleAxisModel = /** @class */function (_super) {
__extends(SingleAxisModel, _super);
function SingleAxisModel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.type = SingleAxisModel.type;
return _this;
}
SingleAxisModel.prototype.getCoordSysModel = function () {
return this;
};
SingleAxisModel.type = COMPONENT_TYPE_SINGLE_AXIS;
SingleAxisModel.layoutMode = 'box';
SingleAxisModel.defaultOption = {
left: '5%',
top: '5%',
right: '5%',
bottom: '5%',
type: 'value',
position: 'bottom',
orient: 'horizontal',
axisLine: {
show: true,
lineStyle: {
width: 1,
type: 'solid'
}
},
// Single coordinate system and single axis is the,
// which is used as the parent tooltip model.
// same model, so we set default tooltip show as true.
tooltip: {
show: true
},
axisTick: {
show: true,
length: 6,
lineStyle: {
width: 1
}
},
axisLabel: {
show: true,
interval: 'auto'
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
opacity: 0.2
}
},
jitter: 0,
jitterOverlap: true,
jitterMargin: 2
};
return SingleAxisModel;
}(ComponentModel);
mixin(SingleAxisModel, AxisModelCommonMixin.prototype);
export default SingleAxisModel;
+199
View File
@@ -0,0 +1,199 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
/**
* Single coordinates system.
*/
import SingleAxis from './SingleAxis.js';
import * as axisHelper from '../axisHelper.js';
import { createBoxLayoutReference, getLayoutRect } from '../../util/layout.js';
import { COORD_SYS_TYPE_SINGLE } from './AxisModel.js';
import { scaleCalcNice } from '../axisNiceTicks.js';
import { AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE, scaleRawExtentInfoCreate } from '../scaleRawExtentInfo.js';
export var singleDimensions = ['single'];
/**
* Create a single coordinates system.
*/
var Single = /** @class */function () {
function Single(axisModel, ecModel, api) {
this.type = COORD_SYS_TYPE_SINGLE;
this.dimension = 'single';
/**
* Add it just for draw tooltip.
*/
this.dimensions = singleDimensions;
this.axisPointerEnabled = true;
this.model = axisModel;
this._init(axisModel, ecModel, api);
}
/**
* Initialize single coordinate system.
*/
Single.prototype._init = function (axisModel, ecModel, api) {
var dim = this.dimension;
var axisType = axisHelper.determineAxisType(axisModel);
var axis = new SingleAxis(dim, axisHelper.createScaleByModel(axisModel, axisType, true), [0, 0], axisType, axisModel.get('position'));
axis.onBand = axisHelper.isAxisOnBand(axis.scale, axisModel);
axis.inverse = axisModel.get('inverse');
axis.orient = axisModel.get('orient');
axisModel.axis = axis;
axis.model = axisModel;
axis.coordinateSystem = this;
this._axis = axis;
};
/**
* Update axis scale after data processed
*/
Single.prototype.update = function (ecModel, api) {
var axis = this._axis;
scaleRawExtentInfoCreate(axis, AXIS_EXTENT_INFO_BUILD_FROM_COORD_SYS_UPDATE);
scaleCalcNice(axis);
};
/**
* Resize the single coordinate system.
*/
Single.prototype.resize = function (axisModel, api) {
var refContainer = createBoxLayoutReference(axisModel, api).refContainer;
this._rect = getLayoutRect(axisModel.getBoxLayoutParams(), refContainer);
this._adjustAxis();
};
Single.prototype.getRect = function () {
return this._rect;
};
Single.prototype._adjustAxis = function () {
var rect = this._rect;
var axis = this._axis;
var isHorizontal = axis.isHorizontal();
var extent = isHorizontal ? [0, rect.width] : [0, rect.height];
var idx = axis.inverse ? 1 : 0;
axis.setExtent(extent[idx], extent[1 - idx]);
this._updateAxisTransform(axis, isHorizontal ? rect.x : rect.y);
};
Single.prototype._updateAxisTransform = function (axis, coordBase) {
var axisExtent = axis.getExtent();
var extentSum = axisExtent[0] + axisExtent[1];
var isHorizontal = axis.isHorizontal();
axis.toGlobalCoord = isHorizontal ? function (coord) {
return coord + coordBase;
} : function (coord) {
return extentSum - coord + coordBase;
};
axis.toLocalCoord = isHorizontal ? function (coord) {
return coord - coordBase;
} : function (coord) {
return extentSum - coord + coordBase;
};
};
/**
* Get axis.
*/
Single.prototype.getAxis = function () {
return this._axis;
};
/**
* Get axis, add it just for draw tooltip.
*/
Single.prototype.getBaseAxis = function () {
return this._axis;
};
Single.prototype.getAxes = function () {
return [this._axis];
};
Single.prototype.getTooltipAxes = function () {
return {
baseAxes: [this.getAxis()],
// Empty otherAxes
otherAxes: []
};
};
/**
* If contain point.
*/
Single.prototype.containPoint = function (point) {
var rect = this.getRect();
var axis = this.getAxis();
var orient = axis.orient;
if (orient === 'horizontal') {
return axis.contain(axis.toLocalCoord(point[0])) && point[1] >= rect.y && point[1] <= rect.y + rect.height;
} else {
return axis.contain(axis.toLocalCoord(point[1])) && point[0] >= rect.y && point[0] <= rect.y + rect.height;
}
};
Single.prototype.pointToData = function (point, reserved, out) {
out = out || [];
var axis = this.getAxis();
out[0] = axis.coordToData(axis.toLocalCoord(point[axis.orient === 'horizontal' ? 0 : 1]));
return out;
};
/**
* Convert the series data to concrete point.
* Can be [val] | val
*/
Single.prototype.dataToPoint = function (val, reserved, out) {
var axis = this.getAxis();
var rect = this.getRect();
out = out || [];
var idx = axis.orient === 'horizontal' ? 0 : 1;
if (val instanceof Array) {
val = val[0];
}
out[idx] = axis.toGlobalCoord(axis.dataToCoord(+val));
out[1 - idx] = idx === 0 ? rect.y + rect.height / 2 : rect.x + rect.width / 2;
return out;
};
Single.prototype.convertToPixel = function (ecModel, finder, value) {
var coordSys = getCoordSys(finder);
return coordSys === this ? this.dataToPoint(value) : null;
};
Single.prototype.convertFromPixel = function (ecModel, finder, pixel) {
var coordSys = getCoordSys(finder);
return coordSys === this ? this.pointToData(pixel) : null;
};
return Single;
}();
function getCoordSys(finder) {
var seriesModel = finder.seriesModel;
var singleModel = finder.singleAxisModel;
return singleModel && singleModel.coordinateSystem || seriesModel && seriesModel.coordinateSystem;
}
export default Single;
+66
View File
@@ -0,0 +1,66 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { __extends } from "tslib";
import Axis from '../Axis.js';
var SingleAxis = /** @class */function (_super) {
__extends(SingleAxis, _super);
function SingleAxis(dim, scale, coordExtent, axisType, position) {
var _this = _super.call(this, dim, scale, coordExtent) || this;
_this.type = axisType || 'value';
_this.position = position || 'bottom';
return _this;
}
/**
* Judge the orient of the axis.
*/
SingleAxis.prototype.isHorizontal = function () {
var position = this.position;
return position === 'top' || position === 'bottom';
};
SingleAxis.prototype.pointToData = function (point, clamp) {
return this.coordinateSystem.pointToData(point)[0];
};
return SingleAxis;
}(Axis);
export default SingleAxis;
+71
View File
@@ -0,0 +1,71 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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 { calcBandWidth } from '../axisBand.js';
import { bind } from 'zrender/lib/core/util.js';
function dataToCoordSize(dataSize, dataItem) {
// dataItem is necessary in log axis.
var axis = this.getAxis();
var val = dataItem instanceof Array ? dataItem[0] : dataItem;
var halfSize = (dataSize instanceof Array ? dataSize[0] : dataSize) / 2;
return axis.type === 'category' ? calcBandWidth(axis).w : Math.abs(axis.dataToCoord(val - halfSize) - axis.dataToCoord(val + halfSize));
}
export default function singlePrepareCustom(coordSys) {
var rect = coordSys.getRect();
return {
coordSys: {
type: 'singleAxis',
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height
},
api: {
coord: function (val) {
// do not provide "out" param
return coordSys.dataToPoint(val);
},
size: bind(dataToCoordSize, coordSys)
}
};
}
+87
View File
@@ -0,0 +1,87 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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/lib/core/util.js';
export function layout(axisModel, opt) {
opt = opt || {};
var single = axisModel.coordinateSystem;
var axis = axisModel.axis;
var layout = {};
var axisPosition = axis.position;
var orient = axis.orient;
var rect = single.getRect();
var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];
var positionMap = {
horizontal: {
top: rectBound[2],
bottom: rectBound[3]
},
vertical: {
left: rectBound[0],
right: rectBound[1]
}
};
layout.position = [orient === 'vertical' ? positionMap.vertical[axisPosition] : rectBound[0], orient === 'horizontal' ? positionMap.horizontal[axisPosition] : rectBound[3]];
var r = {
horizontal: 0,
vertical: 1
};
layout.rotation = Math.PI / 2 * r[orient];
var directionMap = {
top: -1,
bottom: 1,
right: 1,
left: -1
};
layout.labelDirection = layout.tickDirection = layout.nameDirection = directionMap[axisPosition];
if (axisModel.get(['axisTick', 'inside'])) {
layout.tickDirection = -layout.tickDirection;
}
if (zrUtil.retrieve(opt.labelInside, axisModel.get(['axisLabel', 'inside']))) {
layout.labelDirection = -layout.labelDirection;
}
var labelRotate = axisModel.get(['axisLabel', 'rotate']);
layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate;
layout.z2 = 1;
return layout;
}
+78
View File
@@ -0,0 +1,78 @@
/*
* 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.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* 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.
*/
/**
* Single coordinate system creator.
*/
import Single, { singleDimensions } from './Single.js';
import { COMPONENT_TYPE_SINGLE_AXIS, COORD_SYS_TYPE_SINGLE, COORD_SYS_TYPE_SINGLE_AXIS_COMPATIBLE } from './AxisModel.js';
import { SINGLE_REFERRING } from '../../util/model.js';
import { associateSeriesWithAxis } from '../axisStatistics.js';
/**
* Create single coordinate system and inject it into seriesModel.
*/
function create(ecModel, api) {
var singles = [];
ecModel.eachComponent(COMPONENT_TYPE_SINGLE_AXIS, function (axisModel, idx) {
var single = new Single(axisModel, ecModel, api);
single.name = 'single_' + idx;
single.resize(axisModel, api);
axisModel.coordinateSystem = single;
singles.push(single);
});
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.get('coordinateSystem') === COORD_SYS_TYPE_SINGLE_AXIS_COMPATIBLE) {
var singleAxisModel = seriesModel.getReferringComponents(COMPONENT_TYPE_SINGLE_AXIS, SINGLE_REFERRING).models[0];
var single = seriesModel.coordinateSystem = singleAxisModel && singleAxisModel.coordinateSystem;
if (single) {
associateSeriesWithAxis(single.getAxis(), seriesModel, COORD_SYS_TYPE_SINGLE);
}
}
});
return singles;
}
var singleCreator = {
create: create,
dimensions: singleDimensions
};
export default singleCreator;