define(function (require) { var layout = require('../../util/layout'); var number = require('../../util/number'); var parsePercent = number.parsePercent; function getViewRect(seriesModel, api) { return layout.getLayoutRect( seriesModel.getBoxLayoutOption(), { width: api.getWidth(), height: api.getHeight() } ); } function getSortedIndices(data, sort) { var valueArr = data.mapArray('value', function (val) { return val; }); var indices = []; var isAscending = sort === 'ascending'; for (var i = 0, len = data.count(); i < len; i++) { indices[i] = i; } indices.sort(function (a, b) { return isAscending ? valueArr[a] - valueArr[b] : valueArr[b] - valueArr[a]; }); return indices; } function labelLayout (data) { data.each(function (idx) { var itemModel = data.getItemModel(idx); var labelModel = itemModel.getModel('label.normal'); var labelPosition = labelModel.get('position'); var labelLineModel = itemModel.getModel('labelLine.normal'); var layout = data.getItemLayout(idx); var points = layout.points; var isLabelInside = labelPosition === 'inner' || labelPosition === 'inside' || labelPosition === 'center'; var textAlign; var textX; var textY; var linePoints; if (isLabelInside) { textX = (points[0][0] + points[1][0] + points[2][0] + points[3][0]) / 4; textY = (points[0][1] + points[1][1] + points[2][1] + points[3][1]) / 4; textAlign = 'center'; linePoints = [ [textX, textY], [textX, textY] ]; } else { var x1; var y1; var x2; var labelLineLen = labelLineModel.get('length'); if (labelPosition === 'left') { // Left side x1 = (points[3][0] + points[0][0]) / 2; y1 = (points[3][1] + points[0][1]) / 2; x2 = x1 - labelLineLen; textX = x2 - 5; textAlign = 'right'; } else { // Right side x1 = (points[1][0] + points[2][0]) / 2; y1 = (points[1][1] + points[2][1]) / 2; x2 = x1 + labelLineLen; textX = x2 + 5; textAlign = 'left'; } var y2 = y1; linePoints = [[x1, y1], [x2, y2]]; textY = y2; } layout.label = { linePoints: linePoints, x: textX, y: textY, textBaseline: 'middle', textAlign: textAlign, inside: isLabelInside }; }); } return function (ecModel, api) { ecModel.eachSeriesByType('funnel', function (seriesModel) { var data = seriesModel.getData(); var sort = seriesModel.get('sort'); var viewRect = getViewRect(seriesModel, api); var indices = getSortedIndices(data, sort); var sizeExtent = [ parsePercent(seriesModel.get('minSize'), viewRect.width), parsePercent(seriesModel.get('maxSize'), viewRect.width) ]; var dataExtent = data.getDataExtent('value'); var min = seriesModel.get('min'); var max = seriesModel.get('max'); if (min == null) { min = Math.min(dataExtent[0], 0); } if (max == null) { max = dataExtent[1]; } var funnelAlign = seriesModel.get('funnelAlign'); var gap = seriesModel.get('gap'); var itemHeight = (viewRect.height - gap * (data.count() - 1)) / data.count(); var y = viewRect.y; var getLinePoints = function (idx, offY) { // End point index is data.count() and we assign it 0 var val = data.get('value', idx) || 0; var itemWidth = number.linearMap(val, [min, max], sizeExtent, true); var x0; switch (funnelAlign) { case 'left': x0 = viewRect.x; break; case 'center': x0 = viewRect.x + (viewRect.width - itemWidth) / 2; break; case 'right': x0 = viewRect.x + viewRect.width - itemWidth; break; } return [ [x0, offY], [x0 + itemWidth, offY] ]; }; if (sort === 'ascending') { // From bottom to top itemHeight = -itemHeight; gap = -gap; y += viewRect.height; indices = indices.reverse(); } for (var i = 0; i < indices.length; i++) { var idx = indices[i]; var nextIdx = indices[i + 1]; var start = getLinePoints(idx, y); var end = getLinePoints(nextIdx, y + itemHeight); y += itemHeight + gap; data.setItemLayout(idx, { points: start.concat(end.slice().reverse()) }); } labelLayout(data); }); }; });