ecModel.eachSeriesByType('sankey', function (seriesModel) { var nodeWidth = seriesModel.get('nodeWidth'); var nodeGap = seriesModel.get('nodeGap'); var layoutInfo = getViewRect(seriesModel, api); seriesModel.layoutInfo = layoutInfo; var width = layoutInfo.width; var height = layoutInfo.height; var graph = seriesModel.getGraph(); var nodes = graph.nodes; var edges = graph.edges; computeNodeValues(nodes); var filteredNodes = zrUtil.filter(nodes, function (node) { return node.getLayout().value === 0; }); var iterations = filteredNodes.length !== 0 ? 0 : seriesModel.get('layoutIterations'); var orient = seriesModel.get('orient'); var nodeAlign = seriesModel.get('nodeAlign'); layoutSankey(nodes, edges, nodeWidth, nodeGap, width, height, iterations, orient, nodeAlign); });
function createList(coordSys, seriesModel, mpModel) { var coordDimsInfos; if (coordSys) { coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) { var info = seriesModel.getData().getDimensionInfo(seriesModel.getData().mapDimension(coordDim)) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys return zrUtil.defaults({ name: coordDim }, info); }); } else { coordDimsInfos = [{ name: 'value', type: 'float' }]; } var mpData = new List(coordDimsInfos, mpModel); var dataOpt = zrUtil.map(mpModel.get('data'), zrUtil.curry(markerHelper.dataTransform, seriesModel)); if (coordSys) { dataOpt = zrUtil.filter(dataOpt, zrUtil.curry(markerHelper.dataFilter, coordSys)); } mpData.initData(dataOpt, null, coordSys ? markerHelper.dimValueGetter : function (item) { return item.value; }); return mpData; }
getInitialData: function (option, ecModel) { var singleAxisModel = ecModel.queryComponents({ mainType: 'singleAxis', index: this.get('singleAxisIndex'), id: this.get('singleAxisId') })[0]; var axisType = singleAxisModel.get('type'); // filter the data item with the value of label is undefined var filterData = zrUtil.filter(option.data, function (dataItem) { return dataItem[2] !== undefined; }); // ??? TODO design a stage to transfer data for themeRiver and lines? var data = this.fixData(filterData || []); var nameList = []; var nameMap = this.nameMap = zrUtil.createHashMap(); var count = 0; for (var i = 0; i < data.length; ++i) { nameList.push(data[i][DATA_NAME_INDEX]); if (!nameMap.get(data[i][DATA_NAME_INDEX])) { nameMap.set(data[i][DATA_NAME_INDEX], count); count++; } } var dimensionsInfo = createDimensions(data, { coordDimensions: ['single'], dimensionsDefine: [ { name: 'time', type: getDimensionTypeByAxis(axisType) }, { name: 'value', type: 'float' }, { name: 'name', type: 'ordinal' } ], encodeDefine: { single: 0, value: 1, itemName: 2 } }); var list = new List(dimensionsInfo, this); list.initData(data); return list; },
/** * @inner * @param {module:echarts/coord/*} coordSys * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/model/Model} mpModel */ function createList(coordSys, seriesModel, mlModel) { var coordDimsInfos; if (coordSys) { coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) { var info = seriesModel.getData().getDimensionInfo( seriesModel.getData().mapDimension(coordDim) ) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys info.name = coordDim; return info; }); } else { coordDimsInfos =[{ name: 'value', type: 'float' }]; } var fromData = new List(coordDimsInfos, mlModel); var toData = new List(coordDimsInfos, mlModel); // No dimensions var lineData = new List([], mlModel); var optData = zrUtil.map(mlModel.get('data'), zrUtil.curry( markLineTransform, seriesModel, coordSys, mlModel )); if (coordSys) { optData = zrUtil.filter( optData, zrUtil.curry(markLineFilter, coordSys) ); } var dimValueGetter = coordSys ? markerHelper.dimValueGetter : function (item) { return item.value; }; fromData.initData( zrUtil.map(optData, function (item) { return item[0]; }), null, dimValueGetter ); toData.initData( zrUtil.map(optData, function (item) { return item[1]; }), null, dimValueGetter ); lineData.initData( zrUtil.map(optData, function (item) { return item[2]; }) ); lineData.hasItemOption = true; return { from: fromData, to: toData, line: lineData }; }
_initDimensions: function () { var dimensions = this.dimensions = []; var parallelAxisIndex = this.parallelAxisIndex = []; var axisModels = zrUtil.filter(this.dependentModels.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); }); }
/** * @param {module:echarts/model/Global} * @return {Object} * @inner */ function getContentFromModel(ecModel) { var result = groupSeries(ecModel); return { value: zrUtil.filter([ assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis), assembleOtherSeries(result.other) ], function (str) { return str.replace(/[\n\t\s]/g, ''); }).join('\n\n' + BLOCK_SPLITER + '\n\n'), meta: result.meta }; }
/** * Set area to each child, and calculate data extent for visual coding. */ function initChildren(node, nodeModel, totalArea, options, hideChildren, depth) { var viewChildren = node.children || []; var orderBy = options.sort; orderBy !== 'asc' && orderBy !== 'desc' && (orderBy = null); var overLeafDepth = options.leafDepth != null && options.leafDepth <= depth; // leafDepth has higher priority. if (hideChildren && !overLeafDepth) { return (node.viewChildren = []); } // Sort children, order by desc. viewChildren = zrUtil.filter(viewChildren, function (child) { return !child.isRemoved(); }); sort(viewChildren, orderBy); var info = statistic(nodeModel, viewChildren, orderBy); if (info.sum === 0) { return (node.viewChildren = []); } info.sum = filterByThreshold(nodeModel, totalArea, info.sum, orderBy, viewChildren); if (info.sum === 0) { return (node.viewChildren = []); } // Set area to each child. for (var i = 0, len = viewChildren.length; i < len; i++) { var area = viewChildren[i].getValue() / info.sum * totalArea; // Do not use setLayout({...}, true), because it is needed to clear last layout. viewChildren[i].setLayout({area: area}); } if (overLeafDepth) { viewChildren.length && node.setLayout({isLeafRoot: true}, true); viewChildren.length = 0; } node.viewChildren = viewChildren; node.setLayout({dataExtent: info.dataExtent}, true); return viewChildren; }
/** * @inner * @param {module:echarts/coord/*} coordSys * @param {module:echarts/model/Series} seriesModel * @param {module:echarts/model/Model} mpModel */ function createList(coordSys, seriesModel, maModel) { var coordDimsInfos; var areaData; var dims = ['x0', 'y0', 'x1', 'y1']; if (coordSys) { coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) { var data = seriesModel.getData(); var info = data.getDimensionInfo( data.mapDimension(coordDim) ) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys return zrUtil.defaults({name: coordDim}, info); }); areaData = new List(zrUtil.map(dims, function (dim, idx) { return { name: dim, type: coordDimsInfos[idx % 2].type }; }), maModel); } else { coordDimsInfos =[{ name: 'value', type: 'float' }]; areaData = new List(coordDimsInfos, maModel); } var optData = zrUtil.map(maModel.get('data'), zrUtil.curry( markAreaTransform, seriesModel, coordSys, maModel )); if (coordSys) { optData = zrUtil.filter( optData, zrUtil.curry(markAreaFilter, coordSys) ); } var dimValueGetter = coordSys ? function (item, dimName, dataIndex, dimIndex) { return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2]; } : function (item) { return item.value; }; areaData.initData(optData, null, dimValueGetter); areaData.hasItemOption = true; return areaData; }
export function adjustScaleForOverflow(min, max, model) { var ecModel = model.ecModel; // Get Axis Length var axisExtent = model.axis.getExtent(); var axisLength = axisExtent[1] - axisExtent[0]; // Calculate placement of bars on axis var barWidthAndOffset = calBarWidthAndOffset(zrUtil.filter( ecModel.getSeriesByType('bar'), function (seriesModel) { return !ecModel.isSeriesFiltered(seriesModel) && seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d'; } )); // Get bars on current base axis and calculate min and max overflow var baseAxisKey = model.axis.dim + model.axis.index; var barsOnCurrentAxis = barWidthAndOffset[baseAxisKey]; if (barsOnCurrentAxis === undefined) { return {min: min, max: max}; } var minOverflow = Infinity; zrUtil.each(barsOnCurrentAxis, function (item) { minOverflow = Math.min(item.offset, minOverflow); }); var maxOverflow = -Infinity; zrUtil.each(barsOnCurrentAxis, function (item) { maxOverflow = Math.max(item.offset + item.width, maxOverflow); }); minOverflow = Math.abs(minOverflow); maxOverflow = Math.abs(maxOverflow); var totalOverFlow = minOverflow + maxOverflow; // Calulate required buffer based on old range and overflow var oldRange = max - min; var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength); var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange); max += overflowBuffer * (maxOverflow / totalOverFlow); min -= overflowBuffer * (minOverflow / totalOverFlow); return {min: min, max: max}; }
/** * @param {string} seriesType * @param {module:echarts/model/Global} ecModel * @param {module:echarts/ExtensionAPI} api */ function barLayoutPolar(seriesType, ecModel, api) { var width = api.getWidth(); var height = api.getHeight(); var lastStackCoords = {}; var barWidthAndOffset = calRadialBar( zrUtil.filter( ecModel.getSeriesByType(seriesType), function (seriesModel) { return !ecModel.isSeriesFiltered(seriesModel) && seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'polar'; } ) ); ecModel.eachSeriesByType(seriesType, function (seriesModel) { // Check series coordinate, do layout for polar only if (seriesModel.coordinateSystem.type !== 'polar') { return; } var data = seriesModel.getData(); var polar = seriesModel.coordinateSystem; var baseAxis = polar.getBaseAxis(); var stackId = getSeriesStackId(seriesModel); var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId]; var columnOffset = columnLayoutInfo.offset; var columnWidth = columnLayoutInfo.width; var valueAxis = polar.getOtherAxis(baseAxis); var center = seriesModel.get('center') || ['50%', '50%']; var cx = parsePercent(center[0], width); var cy = parsePercent(center[1], height); var barMinHeight = seriesModel.get('barMinHeight') || 0; var barMinAngle = seriesModel.get('barMinAngle') || 0; lastStackCoords[stackId] = lastStackCoords[stackId] || []; var valueDim = data.mapDimension(valueAxis.dim); var baseDim = data.mapDimension(baseAxis.dim); var stacked = isDimensionStacked(data, valueDim /*, baseDim*/); var valueAxisStart = valueAxis.getExtent()[0]; for (var idx = 0, len = data.count(); idx < len; idx++) { var value = data.get(valueDim, idx); var baseValue = data.get(baseDim, idx); if (isNaN(value)) { continue; } var sign = value >= 0 ? 'p' : 'n'; var baseCoord = valueAxisStart; // Because of the barMinHeight, we can not use the value in // stackResultDimension directly. // Only ordinal axis can be stacked. if (stacked) { if (!lastStackCoords[stackId][baseValue]) { lastStackCoords[stackId][baseValue] = { p: valueAxisStart, // Positive stack n: valueAxisStart // Negative stack }; } // Should also consider #4243 baseCoord = lastStackCoords[stackId][baseValue][sign]; } var r0; var r; var startAngle; var endAngle; // radial sector if (valueAxis.dim === 'radius') { var radiusSpan = valueAxis.dataToRadius(value) - valueAxisStart; var angle = baseAxis.dataToAngle(baseValue); if (Math.abs(radiusSpan) < barMinHeight) { radiusSpan = (radiusSpan < 0 ? -1 : 1) * barMinHeight; } r0 = baseCoord; r = baseCoord + radiusSpan; startAngle = angle - columnOffset; endAngle = startAngle - columnWidth; stacked && (lastStackCoords[stackId][baseValue][sign] = r); } // tangential sector else { // angleAxis must be clamped. var angleSpan = valueAxis.dataToAngle(value, true) - valueAxisStart; var radius = baseAxis.dataToRadius(baseValue); if (Math.abs(angleSpan) < barMinAngle) { angleSpan = (angleSpan < 0 ? -1 : 1) * barMinAngle; } r0 = radius + columnOffset; r = r0 + columnWidth; startAngle = baseCoord; endAngle = baseCoord + angleSpan; // if the previous stack is at the end of the ring, // add a round to differentiate it from origin // var extent = angleAxis.getExtent(); // var stackCoord = angle; // if (stackCoord === extent[0] && value > 0) { // stackCoord = extent[1]; // } // else if (stackCoord === extent[1] && value < 0) { // stackCoord = extent[0]; // } stacked && (lastStackCoords[stackId][baseValue][sign] = endAngle); } data.setItemLayout(idx, { cx: cx, cy: cy, r0: r0, r: r, // Consider that positive angle is anti-clockwise, // while positive radian of sector is clockwise startAngle: -startAngle * Math.PI / 180, endAngle: -endAngle * Math.PI / 180 }); } }, this); }
export function getScaleExtent(scale, model) { var scaleType = scale.type; var min = model.getMin(); var max = model.getMax(); var fixMin = min != null; var fixMax = max != null; var originalExtent = scale.getExtent(); var axisDataLen; var boundaryGap; var span; if (scaleType === 'ordinal') { axisDataLen = model.getCategories().length; } else { boundaryGap = model.get('boundaryGap'); if (!zrUtil.isArray(boundaryGap)) { boundaryGap = [boundaryGap || 0, boundaryGap || 0]; } if (typeof boundaryGap[0] === 'boolean') { if (__DEV__) { 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 be 0.'); } boundaryGap = [0, 0]; } boundaryGap[0] = numberUtil.parsePercent(boundaryGap[0], 1); boundaryGap[1] = numberUtil.parsePercent(boundaryGap[1], 1); span = (originalExtent[1] - originalExtent[0]) || Math.abs(originalExtent[0]); } // 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 `needCrossZero`, 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. // FIXME // (1) When min/max is 'dataMin' or 'dataMax', should boundaryGap be able to used? // (2) When `needCrossZero` and all data is positive/negative, should it be ensured // that the results processed by boundaryGap are positive/negative? if (min == null) { min = scaleType === 'ordinal' ? (axisDataLen ? 0 : NaN) : originalExtent[0] - boundaryGap[0] * span; } if (max == null) { max = scaleType === 'ordinal' ? (axisDataLen ? axisDataLen - 1 : NaN) : originalExtent[1] + boundaryGap[1] * span; } if (min === 'dataMin') { min = originalExtent[0]; } else if (typeof min === 'function') { min = min({ min: originalExtent[0], max: originalExtent[1] }); } if (max === 'dataMax') { max = originalExtent[1]; } else if (typeof max === 'function') { max = max({ min: originalExtent[0], max: originalExtent[1] }); } (min == null || !isFinite(min)) && (min = NaN); (max == null || !isFinite(max)) && (max = NaN); scale.setBlank(zrUtil.eqNaN(min) || zrUtil.eqNaN(max)); // Evaluate if axis needs cross zero if (model.getNeedCrossZero()) { // Axis is over zero and min is not set if (min > 0 && max > 0 && !fixMin) { min = 0; } // Axis is under zero and max is not set if (min < 0 && max < 0 && !fixMax) { max = 0; } } // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis // is base axis var ecModel = model.ecModel; if (ecModel) { var isBaseAxisAndHasBarSeries = zrUtil.filter(ecModel.getSeriesByType('bar'), function (seriesModel) { return seriesModel.getBaseAxis() === model.axis; }).length > 0; if ((scaleType === 'time' || scaleType === 'interval') && isBaseAxisAndHasBarSeries) { // Adjust axis min and max to account for overflow var adjustedScale = adjustScaleForOverflow(min, max, model); min = adjustedScale.min; max = adjustedScale.max; } } return [min, max]; }