UNPKG

light-chart

Version:

Charts for mobile visualization.

341 lines (309 loc) 9.2 kB
const Util = require('../../util/common'); const Axis = require('../../component/axis/'); const Global = require('../../global'); const { Shape } = require('../../graphic/index'); function formatTicks(ticks) { const tmp = ticks.slice(0); if (tmp.length > 0) { const first = tmp[0]; const last = tmp[tmp.length - 1]; if (first.value !== 0) { tmp.unshift({ value: 0 }); } if (last.value !== 1) { tmp.push({ value: 1 }); } } return tmp; } class AxisController { constructor(cfg) { this.axisCfg = {}; this.frontPlot = null; this.backPlot = null; this.axes = {}; // store the axes's options Util.mix(this, cfg); } _isHide(field) { const axisCfg = this.axisCfg; return !axisCfg || axisCfg[field] === false; } _getLinePosition(scale, dimType, index, transposed) { let position = ''; const field = scale.field; const axisCfg = this.axisCfg; if (axisCfg[field] && axisCfg[field].position) { position = axisCfg[field].position; } else if (dimType === 'x') { position = transposed ? 'left' : 'bottom'; } else if (dimType === 'y') { position = index ? 'right' : 'left'; if (transposed) { position = 'bottom'; } } return position; } _getLineCfg(coord, dimType, position) { let start; let end; let factor = 1; // Mark clockwise or counterclockwise if (dimType === 'x') { start = { x: 0, y: 0 }; end = { x: 1, y: 0 }; } else { if (position === 'right') { // there will be several y axes start = { x: 1, y: 0 }; end = { x: 1, y: 1 }; } else { start = { x: 0, y: 0 }; end = { x: 0, y: 1 }; factor = -1; } } if (coord.transposed) { factor *= -1; } return { offsetFactor: factor, start: coord.convertPoint(start), end: coord.convertPoint(end) }; } _getCircleCfg(coord) { return { startAngle: coord.startAngle, endAngle: coord.endAngle, center: coord.center, radius: coord.circleRadius }; } _getRadiusCfg(coord) { const transposed = coord.transposed; let start; let end; if (transposed) { start = { x: 0, y: 0 }; end = { x: 1, y: 0 }; } else { start = { x: 0, y: 0 }; end = { x: 0, y: 1 }; } return { offsetFactor: -1, start: coord.convertPoint(start), end: coord.convertPoint(end) }; } _getAxisCfg(coord, scale, verticalScale, dimType, defaultCfg) { const self = this; const axisCfg = this.axisCfg; const ticks = scale.getTicks(); const cfg = Util.deepMix({ ticks, frontContainer: this.frontPlot, backContainer: this.backPlot }, defaultCfg, axisCfg[scale.field]); const labels = []; const label = cfg.label; const count = ticks.length; let maxWidth = 0; let maxHeight = 0; let labelCfg = label; Util.each(ticks, (tick, index) => { if (Util.isFunction(label)) { const executedLabel = label(tick.text, index, count); labelCfg = executedLabel ? Util.mix({}, Global._defaultAxis.label, executedLabel) : null; } if (labelCfg) { const textStyle = {}; if (labelCfg.textAlign) { textStyle.textAlign = labelCfg.textAlign; } if (labelCfg.textBaseline) { textStyle.textBaseline = labelCfg.textBaseline; } const axisLabel = new Shape.Text({ className: 'axis-label', attrs: Util.mix({ x: 0, y: 0, text: tick.text, fontFamily: self.chart.get('canvas').get('fontFamily') }, labelCfg), value: tick.value, textStyle, top: labelCfg.top, context: self.chart.get('canvas').get('context') }); labels.push(axisLabel); const { width, height } = axisLabel.getBBox(); maxWidth = Math.max(maxWidth, width); maxHeight = Math.max(maxHeight, height); } }); cfg.labels = labels; cfg.maxWidth = maxWidth; cfg.maxHeight = maxHeight; return cfg; } _createAxis(coord, scale, verticalScale, dimType, index = '') { const self = this; const coordType = coord.type; const transposed = coord.transposed; let type; let key; let defaultCfg; if (coordType === 'cartesian' || coordType === 'rect') { const position = self._getLinePosition(scale, dimType, index, transposed); defaultCfg = Global.axis[position]; defaultCfg.position = position; type = 'Line'; key = position; } else { if ((dimType === 'x' && !transposed) || (dimType === 'y' && transposed)) { defaultCfg = Global.axis.circle; type = 'Circle'; key = 'circle'; } else { defaultCfg = Global.axis.radius; type = 'Line'; key = 'radius'; } } const cfg = self._getAxisCfg(coord, scale, verticalScale, dimType, defaultCfg); cfg.type = type; cfg.dimType = dimType; cfg.verticalScale = verticalScale; cfg.index = index; this.axes[key] = cfg; } createAxis(coord, xScale, yScales) { const self = this; if (xScale && !self._isHide(xScale.field)) { self._createAxis(coord, xScale, yScales[0], 'x'); } Util.each(yScales, function(yScale, index) { if (!self._isHide(yScale.field)) { self._createAxis(coord, yScale, xScale, 'y', index); } }); const axes = this.axes; const chart = self.chart; if (chart._isAutoPadding()) { const userPadding = Util.parsePadding(chart.get('padding')); const appendPadding = Util.parsePadding(chart.get('appendPadding')); const legendRange = chart.get('legendRange') || { top: 0, right: 0, bottom: 0, left: 0 }; const padding = [ userPadding[0] === 'auto' ? legendRange.top + appendPadding[0] * 2 : userPadding[0], userPadding[1] === 'auto' ? legendRange.right + appendPadding[1] : userPadding[1], userPadding[2] === 'auto' ? legendRange.bottom + appendPadding[2] : userPadding[2], userPadding[3] === 'auto' ? legendRange.left + appendPadding[3] : userPadding[3] ]; if (coord.isPolar) { const circleAxis = axes.circle; if (circleAxis) { const { maxHeight, maxWidth, labelOffset } = circleAxis; padding[0] += maxHeight + labelOffset; padding[1] += maxWidth + labelOffset; padding[2] += maxHeight + labelOffset; padding[3] += maxWidth + labelOffset; } } else { if (axes.right && userPadding[1] === 'auto') { const { maxWidth, labelOffset } = axes.right; padding[1] += maxWidth + labelOffset; } if (axes.left && userPadding[3] === 'auto') { const { maxWidth, labelOffset } = axes.left; padding[3] += maxWidth + labelOffset; } if (axes.bottom && userPadding[2] === 'auto') { const { maxHeight, labelOffset } = axes.bottom; padding[2] += maxHeight + labelOffset; } } chart.set('_padding', padding); chart._updateLayout(padding); } Util.each(axes, axis => { const { type, grid, verticalScale, ticks, dimType, position, index } = axis; let appendCfg; if (coord.isPolar) { if (type === 'Line') { appendCfg = self._getRadiusCfg(coord); } else if (type === 'Circle') { appendCfg = self._getCircleCfg(coord); } } else { appendCfg = self._getLineCfg(coord, dimType, position); } if (grid && verticalScale) { const gridPoints = []; const verticalTicks = formatTicks(verticalScale.getTicks()); Util.each(ticks, tick => { const subPoints = []; Util.each(verticalTicks, verticalTick => { const x = dimType === 'x' ? tick.value : verticalTick.value; const y = dimType === 'x' ? verticalTick.value : tick.value; if (x >= 0 && x <= 1 && y >= 0 && y <= 1) { const point = coord.convertPoint({ x, y }); subPoints.push(point); } }); gridPoints.push({ points: subPoints, _id: 'axis-' + dimType + index + '-grid-' + tick.tickValue }); }); axis.gridPoints = gridPoints; if (coord.isPolar) { axis.center = coord.center; axis.startAngle = coord.startAngle; axis.endAngle = coord.endAngle; } } appendCfg._id = 'axis-' + dimType; if (!Util.isNil(index)) { appendCfg._id = 'axis-' + dimType + index; } new Axis[type](Util.mix(axis, appendCfg)); }); } clear() { this.axes = {}; this.frontPlot.clear(); this.backPlot.clear(); } } module.exports = AxisController;