UNPKG

echarts-nightly

Version:

Apache ECharts is a powerful, interactive charting and data visualization library for browser

295 lines (291 loc) • 12 kB
/* * 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 }; }