UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,227 lines (1,031 loc) • 44.5 kB
"use strict"; var noop = require("../core/utils/common").noop, _extend = require("../core/utils/extend").extend, inArray = require("../core/utils/array").inArray, each = require("../core/utils/iterator").each, registerComponent = require("../core/component_registrator"), vizUtils = require("./core/utils"), mathUtils = require("../core/utils/math"), overlapping = require("./chart_components/base_chart").overlapping, LayoutManagerModule = require("./chart_components/layout_manager"), multiAxesSynchronizer = require("./chart_components/multi_axes_synchronizer"), AdvancedChart = require("./chart_components/advanced_chart").AdvancedChart, scrollBarModule = require("./chart_components/scroll_bar"), crosshairModule = require("./chart_components/crosshair"), rangeModule = require("./translators/range"), DEFAULT_PANE_NAME = "default", DEFAULT_PANES = [{ name: DEFAULT_PANE_NAME, border: {} }], _map = vizUtils.map, _each = each, _isArray = Array.isArray, _isDefined = require("../core/utils/type").isDefined; function getFirstAxisNameForPane(axes, paneName, defaultPane) { var result; for (var i = 0; i < axes.length; i++) { if (axes[i].pane === paneName || axes[i].pane === undefined && paneName === defaultPane) { result = axes[i].name; break; } } if (!result) { result = axes[0].name; } return result; } function changeVisibilityAxisGrids(axis, gridVisibility, minorGridVisibility) { var gridOpt = axis.getOptions().grid, minorGridOpt = axis.getOptions().minorGrid; gridOpt.visible = gridVisibility; minorGridOpt && (minorGridOpt.visible = minorGridVisibility); } function hideGridsOnNonFirstValueAxisForPane(axesForPane) { var axisShown = false, hiddenStubAxis = [], minorGridVisibility = axesForPane.some(function (axis) { var minorGridOptions = axis.getOptions().minorGrid; return minorGridOptions && minorGridOptions.visible; }), gridVisibility = axesForPane.some(function (axis) { var gridOptions = axis.getOptions().grid; return gridOptions && gridOptions.visible; }); if (axesForPane.length > 1) { axesForPane.forEach(function (axis) { var gridOpt = axis.getOptions().grid; if (axisShown) { changeVisibilityAxisGrids(axis, false, false); } else if (gridOpt && gridOpt.visible) { if (!axis.getTranslator().getBusinessRange().stubData) { axisShown = true; changeVisibilityAxisGrids(axis, gridVisibility, minorGridVisibility); } else { changeVisibilityAxisGrids(axis, false, false); hiddenStubAxis.push(axis); } } }); !axisShown && hiddenStubAxis.length && changeVisibilityAxisGrids(hiddenStubAxis[0], gridVisibility, minorGridVisibility); } } function findAxisOptions(valueAxes, valueAxesOptions, axisName) { var result, axInd; for (axInd = 0; axInd < valueAxesOptions.length; axInd++) { if (valueAxesOptions[axInd].name === axisName) { result = valueAxesOptions[axInd]; result.priority = axInd; break; } } if (!result) { for (axInd = 0; axInd < valueAxes.length; axInd++) { if (valueAxes[axInd].name === axisName) { result = valueAxes[axInd].getOptions(); result.priority = valueAxes[axInd].priority; break; } } } return result; } function findAxis(paneName, axisName, axes) { var axis, i; for (i = 0; i < axes.length; i++) { axis = axes[i]; if (axis.name === axisName && axis.pane === paneName) { return axis; } } if (paneName) { return findAxis(undefined, axisName, axes); } } function applyClipSettings(clipRects, settings) { _each(clipRects || [], function (_, c) { c && c.attr(settings); }); } function compareAxes(a, b) { return a.priority - b.priority; } // checks if pane with provided name exists in this panes array function doesPaneExist(panes, paneName) { var found = false; _each(panes, function (_, pane) { if (pane.name === paneName) { found = true; return false; } }); return found; } // 'var' because JSHint throws W021 error var prepareSegmentRectPoints = function prepareSegmentRectPoints(left, top, width, height, borderOptions) { var maxSW = ~~((width < height ? width : height) / 2), sw = borderOptions.width || 0, newSW = sw < maxSW ? sw : maxSW; left = left + newSW / 2; top = top + newSW / 2; width = width - newSW; height = height - newSW; var right = left + width, bottom = top + height, points = [], segments = [], segmentSequence, visiblyOpt = 0, prevSegmentVisibility = 0; var allSegment = { top: [[left, top], [right, top]], right: [[right, top], [right, bottom]], bottom: [[right, bottom], [left, bottom]], left: [[left, bottom], [left, top]] }; _each(allSegment, function (seg) { var visibility = !!borderOptions[seg]; visiblyOpt = visiblyOpt * 2 + ~~visibility; }); switch (visiblyOpt) { case 13: case 9: segmentSequence = ["left", "top", "right", "bottom"]; break; case 11: segmentSequence = ["bottom", "left", "top", "right"]; break; default: segmentSequence = ["top", "right", "bottom", "left"]; } _each(segmentSequence, function (_, seg) { var segmentVisibility = !!borderOptions[seg]; if (!prevSegmentVisibility && segments.length) { points.push(segments); segments = []; } if (segmentVisibility) { _each(allSegment[seg].slice(prevSegmentVisibility), function (_, segment) { segments = segments.concat(segment); }); } prevSegmentVisibility = ~~segmentVisibility; }); segments.length && points.push(segments); points.length === 1 && (points = points[0]); return { points: points, pathType: visiblyOpt === 15 ? "area" : "line" }; }; // utilities used in axes rendering function accumulate(field, src1, src2, auxSpacing) { var val1 = src1[field] || 0, val2 = src2[field] || 0; return val1 + val2 + (val1 && val2 ? auxSpacing : 0); } function pickMax(field, src1, src2) { return pickMaxValue(src1[field], src2[field]); } function pickMaxValue(val1, val2) { return Math.max(val1 || 0, val2 || 0); } function getAxisMargins(axis) { return axis.getMargins(); } function getHorizontalAxesMargins(axes, getMarginsFunc) { return axes.reduce(function (margins, axis) { var axisMargins = getMarginsFunc(axis), paneMargins = margins.panes[axis.pane] = margins.panes[axis.pane] || {}, spacing = axis.getMultipleAxesSpacing(); paneMargins.top = accumulate("top", paneMargins, axisMargins, spacing); paneMargins.bottom = accumulate("bottom", paneMargins, axisMargins, spacing); paneMargins.left = pickMax("left", paneMargins, axisMargins); paneMargins.right = pickMax("right", paneMargins, axisMargins); margins.top = pickMax("top", paneMargins, margins); margins.bottom = pickMax("bottom", paneMargins, margins); margins.left = pickMax("left", paneMargins, margins); margins.right = pickMax("right", paneMargins, margins); return margins; }, { panes: {} }); } function getVerticalAxesMargins(axes) { return axes.reduce(function (margins, axis) { var axisMargins = axis.getMargins(), paneMargins = margins.panes[axis.pane] = margins.panes[axis.pane] || {}, spacing = axis.getMultipleAxesSpacing(); paneMargins.top = pickMax("top", paneMargins, axisMargins); paneMargins.bottom = pickMax("bottom", paneMargins, axisMargins); paneMargins.left = accumulate("left", paneMargins, axisMargins, spacing); paneMargins.right = accumulate("right", paneMargins, axisMargins, spacing); margins.top = pickMax("top", paneMargins, margins); margins.bottom = pickMax("bottom", paneMargins, margins); margins.left = pickMax("left", paneMargins, margins); margins.right = pickMax("right", paneMargins, margins); return margins; }, { panes: {} }); } function performActionOnAxes(axes, action, actionArgument1, actionArgument2) { axes.forEach(function (axis) { axis[action](actionArgument1 && actionArgument1[axis.pane], actionArgument2 && actionArgument2[axis.pane]); }); } function shrinkCanvases(isRotated, canvases, verticalMargins, horizontalMargins) { function getMargin(side, margins, pane) { var m = (isRotated ? ["left", "right"] : ["top", "bottom"]).indexOf(side) === -1 ? margins : margins.panes[pane] || {}; return m[side]; } function getMaxMargin(side, margins1, margins2, pane) { return pickMaxValue(getMargin(side, margins1, pane), getMargin(side, margins2, pane)); } for (var pane in canvases) { canvases[pane].top = canvases[pane].originalTop + getMaxMargin("top", verticalMargins, horizontalMargins, pane); canvases[pane].bottom = canvases[pane].originalBottom + getMaxMargin("bottom", verticalMargins, horizontalMargins, pane); canvases[pane].left = canvases[pane].originalLeft + getMaxMargin("left", verticalMargins, horizontalMargins, pane); canvases[pane].right = canvases[pane].originalRight + getMaxMargin("right", verticalMargins, horizontalMargins, pane); } return canvases; } function drawAxesWithTicks(axes, condition, canvases, panesBorderOptions) { if (condition) { performActionOnAxes(axes, "createTicks", canvases); multiAxesSynchronizer.synchronize(axes); } performActionOnAxes(axes, "draw", !condition && canvases, panesBorderOptions); } function shiftAxis(side1, side2) { var shifts = {}; return function (axis) { var shift = shifts[axis.pane] = shifts[axis.pane] || { top: 0, left: 0, bottom: 0, right: 0 }, spacing = axis.getMultipleAxesSpacing(), margins = axis.getMargins(); axis.shift(shift); shift[side1] = accumulate(side1, shift, margins, spacing); shift[side2] = accumulate(side2, shift, margins, spacing); }; } function getCommonSize(side, margins) { var size = 0, pane, paneMargins; for (pane in margins.panes) { paneMargins = margins.panes[pane]; size = size + (side === "height" ? paneMargins.top + paneMargins.bottom : paneMargins.left + paneMargins.right); } return size; } function checkUsedSpace(sizeShortage, side, axes, getMarginFunc) { var size = 0; if (sizeShortage[side] > 0) { size = getCommonSize(side, getMarginFunc(axes, getAxisMargins)); performActionOnAxes(axes, "hideTitle"); sizeShortage[side] -= size - getCommonSize(side, getMarginFunc(axes, getAxisMargins)); } if (sizeShortage[side] > 0) { performActionOnAxes(axes, "hideOuterElements"); } } // utilities used in axes rendering var dxChart = AdvancedChart.inherit({ _chartType: "chart", _setDeprecatedOptions: function _setDeprecatedOptions() { this.callBase.apply(this, arguments); _extend(this._deprecatedOptions, { "argumentAxis.label.overlappingBehavior.rotationAngle": { since: "17.1", message: "Use the 'argumentAxis.label.rotationAngle' option instead" }, "argumentAxis.label.overlappingBehavior.staggeringSpacing": { since: "17.1", message: "Use the 'argumentAxis.label.staggeringSpacing' option instead" }, "argumentAxis.label.overlappingBehavior.mode": { since: "17.1", message: "Use the 'overlappingBehavior' option directly" }, "valueAxis.label.overlappingBehavior.rotationAngle": { since: "17.1", message: "Use the 'valueAxis.label.rotationAngle' option instead" }, "valueAxis.label.overlappingBehavior.staggeringSpacing": { since: "17.1", message: "Use the 'valueAxis.label.staggeringSpacing' option instead" }, "valueAxis.label.overlappingBehavior.mode": { since: "17.1", message: "Use the 'overlappingBehavior' option directly" }, "commonAxisSettings.label.overlappingBehavior.rotationAngle": { since: "17.1", message: "Use the 'commonAxisSettings.label.rotationAngle' option instead" }, "commonAxisSettings.label.overlappingBehavior.staggeringSpacing": { since: "17.1", message: "Use the 'commonAxisSettings.label.staggeringSpacing' option instead" }, "commonAxisSettings.label.overlappingBehavior.mode": { since: "17.1", message: "Use the 'overlappingBehavior' option directly" }, "useAggregation": { since: "18.1", message: "Use the 'commonSeriesSettings.aggregation.enabled' or 'series.aggregation.enabled' option instead" } }); }, _initCore: function _initCore() { this.paneAxis = {}; this._panesClipRects = {}; this.callBase(); }, _disposeCore: function _disposeCore() { var that = this, disposeObjectsInArray = this._disposeObjectsInArray, panesClipRects = that._panesClipRects; that.callBase(); disposeObjectsInArray.call(panesClipRects, "fixed"); disposeObjectsInArray.call(panesClipRects, "base"); disposeObjectsInArray.call(panesClipRects, "wide"); that._panesClipRects = null; }, _correctAxes: function _correctAxes() { this._correctValueAxes(true); }, _getExtraOptions: noop, _cleanPanesClipRects: function _cleanPanesClipRects(clipArrayName) { var that = this, clipArray = that._panesClipRects[clipArrayName]; _each(clipArray || [], function (_, clipRect) { clipRect && clipRect.dispose(); }); that._panesClipRects[clipArrayName] = []; }, _createPanes: function _createPanes() { var that = this, panes = that.option("panes"), panesNameCounter = 0, defaultPane; if (!panes || _isArray(panes) && !panes.length) { panes = DEFAULT_PANES; } that._cleanPanesClipRects("fixed"); that._cleanPanesClipRects("base"); that._cleanPanesClipRects("wide"); defaultPane = that.option("defaultPane"); panes = _extend(true, [], _isArray(panes) ? panes : [panes]); _each(panes, function (_, pane) { pane.name = !_isDefined(pane.name) ? DEFAULT_PANE_NAME + panesNameCounter++ : pane.name; }); if (_isDefined(defaultPane)) { if (!doesPaneExist(panes, defaultPane)) { that._incidentOccurred("W2101", [defaultPane]); defaultPane = panes[panes.length - 1].name; } } else { defaultPane = panes[panes.length - 1].name; } that.defaultPane = defaultPane; panes = that._isRotated() ? panes.reverse() : panes; return panes; }, _getAxisRenderingOptions: function _getAxisRenderingOptions() { return { axisType: "xyAxes", drawingType: "linear" }; }, _prepareAxisOptions: function _prepareAxisOptions(typeSelector, userOptions, rotated) { return { isHorizontal: typeSelector === "argumentAxis" !== rotated, containerColor: this._themeManager.getOptions("containerBackgroundColor") }; }, _checkPaneName: function _checkPaneName(seriesTheme) { var paneList = _map(this.panes, function (pane) { return pane.name; }); seriesTheme.pane = seriesTheme.pane || this.defaultPane; return inArray(seriesTheme.pane, paneList) !== -1; }, _getValueAxis: function _getValueAxis(paneName, axisName) { var that = this, valueAxes = that._valueAxes, valueAxisOptions = that.option("valueAxis") || {}, valueAxesOptions = _isArray(valueAxisOptions) ? valueAxisOptions : [valueAxisOptions], rotated = that._isRotated(), crosshairMargins = that._getCrosshairMargins(), axisOptions, axis; axisName = axisName || getFirstAxisNameForPane(valueAxes, paneName, that.defaultPane); axis = findAxis(paneName, axisName, valueAxes); if (!axis) { axisOptions = findAxisOptions(valueAxes, valueAxesOptions, axisName); if (!axisOptions) { that._incidentOccurred("W2102", [axisName]); axisOptions = { name: axisName, priority: valueAxes.length }; } axis = that._createAxis("valueAxis", axisOptions, { pane: paneName, name: axisName, crosshairMargin: rotated ? crosshairMargins.y : crosshairMargins.x }, rotated); valueAxes.push(axis); } axis.setPane(paneName); return axis; }, _correctValueAxes: function _correctValueAxes(needHideGrids) { var that = this, synchronizeMultiAxes = that._themeManager.getOptions("synchronizeMultiAxes"), valueAxes = that._valueAxes, paneWithAxis = {}; that.series.forEach(function (series) { var axis = series.getValueAxis(); paneWithAxis[axis.pane] = true; }); that.panes.forEach(function (pane) { var paneName = pane.name; if (!paneWithAxis[paneName]) { that._getValueAxis(paneName); // creates an value axis if there is no one for pane } if (needHideGrids && synchronizeMultiAxes) { hideGridsOnNonFirstValueAxisForPane(valueAxes.filter(function (axis) { return axis.pane === paneName; })); } }); that._valueAxes = valueAxes.filter(function (axis) { if (!axis.pane) { axis.setPane(that.defaultPane); } return doesPaneExist(that.panes, axis.pane); }).sort(compareAxes); }, _getSeriesForPane: function _getSeriesForPane(paneName) { var paneSeries = []; _each(this.series, function (_, oneSeries) { if (oneSeries.pane === paneName) { paneSeries.push(oneSeries); } }); return paneSeries; }, _createPanesBorderOptions: function _createPanesBorderOptions() { var commonBorderOptions = this._themeManager.getOptions("commonPaneSettings").border, panesBorderOptions = {}; _each(this.panes, function (_, pane) { panesBorderOptions[pane.name] = _extend(true, {}, commonBorderOptions, pane.border); }); return panesBorderOptions; }, _createScrollBar: function _createScrollBar() { var that = this, scrollBarOptions = that._themeManager.getOptions("scrollBar") || {}, scrollBarGroup = that._scrollBarGroup; if (scrollBarOptions.visible) { scrollBarOptions.rotated = that._isRotated(); that._scrollBar = (that._scrollBar || new scrollBarModule.ScrollBar(that._renderer, scrollBarGroup)).update(scrollBarOptions); } else { scrollBarGroup.linkRemove(); that._scrollBar && that._scrollBar.dispose(); that._scrollBar = null; } }, _prepareToRender: function _prepareToRender(drawOptions) { var panesBorderOptions = this._createPanesBorderOptions(); this._createPanesBackground(); this._appendAxesGroups(); this._transformed && this._resetTransform(); this._updatePanesCanvases(drawOptions); this._adjustViewport(); return panesBorderOptions; }, _adjustViewport: function _adjustViewport() { var that = this; var series = that._getVisibleSeries(); var argumentAxis = that._getArgumentAxis(); var argumentViewport = argumentAxis.getViewport(); var minMaxDefined = argumentViewport && (_isDefined(argumentViewport.min) || _isDefined(argumentViewport.max)); var useAggregation = series.some(function (s) { return s.useAggregation(); }); var adjustOnZoom = that._themeManager.getOptions("adjustOnZoom"); if (!useAggregation && !(minMaxDefined && adjustOnZoom)) { return; } var isArgumentAxisZoomed = argumentAxis.isZoomed(); that._valueAxes.forEach(function (axis) { if (!isArgumentAxisZoomed && axis.isZoomed()) { return; } var viewport = series.filter(function (s) { return s.getValueAxis() === axis; }).reduce(function (range, s) { var seriesRange = s.getViewport(); range.min = _isDefined(seriesRange.min) ? range.min < seriesRange.min ? range.min : seriesRange.min : range.min; range.max = _isDefined(seriesRange.max) ? range.max > seriesRange.max ? range.max : seriesRange.max : range.max; if (s.showZero) { range = new rangeModule.Range(range); range.correctValueZeroLevel(); } return range; }, {}); if (_isDefined(viewport.min) && _isDefined(viewport.max)) { axis.zoom(viewport.min, viewport.max); } }); }, _recreateSizeDependentObjects: function _recreateSizeDependentObjects(isCanvasChanged) { var that = this, series = that._getVisibleSeries(), useAggregation = series.some(function (s) { return s.useAggregation(); }), zoomChanged = that._isZooming(); if (!useAggregation) { return; } that._argumentAxes.forEach(function (axis) { axis.updateCanvas(that._canvas); }); series.forEach(function (series) { if (series.useAggregation() && (isCanvasChanged || zoomChanged || !series._useAllAggregatedPoints)) { series.createPoints(); } }); that._processSeriesFamilies(); }, _isZooming: function _isZooming() { var that = this, argumentAxis = that._getArgumentAxis(); if (!argumentAxis || !argumentAxis.getTranslator()) { return false; } var businessRange = argumentAxis.getTranslator().getBusinessRange(); var min = that._zoomMinArg ? that._zoomMinArg : 0; var max = that._zoomMaxArg ? that._zoomMaxArg : 0; if (businessRange.axisType === "logarithmic") { min = vizUtils.getLog(min, businessRange.base); max = vizUtils.getLog(max, businessRange.base); } var viewportDistance = businessRange.axisType === "discrete" ? vizUtils.getCategoriesInfo(businessRange.categories, min, max).categories.length : Math.abs(max - min); var precision = mathUtils.getPrecision(viewportDistance); precision = precision > 1 ? Math.pow(10, precision - 2) : 1; var zoomChanged = Math.round((that._zoomLength - viewportDistance) * precision) / precision !== 0; that._zoomLength = viewportDistance; return zoomChanged; }, _handleSeriesDataUpdated: function _handleSeriesDataUpdated() { var that = this, viewport = new rangeModule.Range(); that.series.forEach(function (s) { viewport.addRange(s.getArgumentRange()); }); if (!viewport.isDefined()) { viewport.setStubData(that._argumentAxes[0].getOptions().argumentType); } that._argumentAxes.forEach(function (axis) { axis.updateCanvas(that._canvas); axis.setBusinessRange(viewport); }); that.callBase(); }, _isLegendInside: function _isLegendInside() { return this._legend && this._legend.getPosition() === "inside"; }, _isRotated: function _isRotated() { return this._themeManager.getOptions("rotated"); }, _getLayoutTargets: function _getLayoutTargets() { return this.panes; }, _applyClipRects: function _applyClipRects(panesBorderOptions) { var that = this, canvasClipRectID = that._getCanvasClipRectID(), i; that._drawPanesBorders(panesBorderOptions); that._createClipRectsForPanes(); for (i = 0; i < that._argumentAxes.length; i++) { that._argumentAxes[i].applyClipRects(that._getElementsClipRectID(that._argumentAxes[i].pane), canvasClipRectID); } for (i = 0; i < that._valueAxes.length; i++) { that._valueAxes[i].applyClipRects(that._getElementsClipRectID(that._valueAxes[i].pane), canvasClipRectID); } that._fillPanesBackground(); }, _updateLegendPosition: function _updateLegendPosition(drawOptions, legendHasInsidePosition) { var that = this; if (drawOptions.drawLegend && that._legend && legendHasInsidePosition) { var panes = that.panes, newCanvas = _extend({}, panes[0].canvas), layoutManager = new LayoutManagerModule.LayoutManager(); newCanvas.right = panes[panes.length - 1].canvas.right; newCanvas.bottom = panes[panes.length - 1].canvas.bottom; layoutManager.setOptions({ width: 0, height: 0 }); layoutManager.layoutElements([that._legend], newCanvas, noop, [{ canvas: newCanvas }], undefined); } }, _applyExtraSettings: function _applyExtraSettings(series) { var that = this, paneIndex = that._getPaneIndex(series.pane), panesClipRects = that._panesClipRects, wideClipRect = panesClipRects.wide[paneIndex]; series.setClippingParams(panesClipRects.base[paneIndex].id, wideClipRect && wideClipRect.id, that._getPaneBorderVisibility(paneIndex)); }, _updatePanesCanvases: function _updatePanesCanvases(drawOptions) { if (!drawOptions.recreateCanvas) { return; } vizUtils.updatePanesCanvases(this.panes, this._canvas, this._isRotated()); }, _renderScaleBreaks: function _renderScaleBreaks() { this._valueAxes.concat(this._argumentAxes).forEach(function (axis) { axis.drawScaleBreaks(); }); }, _renderAxes: function _renderAxes(drawOptions, panesBorderOptions) { var that = this, rotated = that._isRotated(), synchronizeMultiAxes = that._themeManager.getOptions("synchronizeMultiAxes"), extendedArgAxes = (that._scrollBar ? [that._scrollBar] : []).concat(that._argumentAxes), verticalAxes = rotated ? extendedArgAxes : that._valueAxes, horizontalAxes = rotated ? that._valueAxes : extendedArgAxes, allAxes = verticalAxes.concat(horizontalAxes); that._updatePanesCanvases(drawOptions); var panesCanvases = that.panes.reduce(function (canvases, pane) { canvases[pane.name] = _extend({}, pane.canvas); return canvases; }, {}), cleanPanesCanvases = _extend(true, {}, panesCanvases); if (!drawOptions.adjustAxes) { drawAxesWithTicks(verticalAxes, !rotated && synchronizeMultiAxes, panesCanvases, panesBorderOptions); drawAxesWithTicks(horizontalAxes, rotated && synchronizeMultiAxes, panesCanvases, panesBorderOptions); that._renderScaleBreaks(); return false; } if (that._scrollBar) { that._scrollBar.setPane(that.panes); } var vAxesMargins = { panes: {} }, hAxesMargins = getHorizontalAxesMargins(horizontalAxes, function (axis) { return axis.estimateMargins(panesCanvases[axis.pane]); }); panesCanvases = shrinkCanvases(rotated, panesCanvases, vAxesMargins, hAxesMargins); drawAxesWithTicks(verticalAxes, !rotated && synchronizeMultiAxes, panesCanvases, panesBorderOptions); vAxesMargins = getVerticalAxesMargins(verticalAxes); panesCanvases = shrinkCanvases(rotated, panesCanvases, vAxesMargins, hAxesMargins); drawAxesWithTicks(horizontalAxes, rotated && synchronizeMultiAxes, panesCanvases, panesBorderOptions); hAxesMargins = getHorizontalAxesMargins(horizontalAxes, getAxisMargins); panesCanvases = shrinkCanvases(rotated, panesCanvases, vAxesMargins, hAxesMargins); performActionOnAxes(allAxes, "updateSize", panesCanvases); horizontalAxes.forEach(shiftAxis("top", "bottom")); verticalAxes.forEach(shiftAxis("left", "right")); that._renderScaleBreaks(); that.panes.forEach(function (pane) { _extend(pane.canvas, panesCanvases[pane.name]); }); return cleanPanesCanvases; }, _shrinkAxes: function _shrinkAxes(drawOptions, sizeShortage, panesCanvases) { if (!sizeShortage || !panesCanvases) { return; } var that = this, rotated = that._isRotated(), extendedArgAxes = (that._scrollBar ? [that._scrollBar] : []).concat(that._argumentAxes), verticalAxes = rotated ? extendedArgAxes : that._valueAxes, horizontalAxes = rotated ? that._valueAxes : extendedArgAxes, allAxes = verticalAxes.concat(horizontalAxes); if (sizeShortage.width || sizeShortage.height) { checkUsedSpace(sizeShortage, "height", horizontalAxes, getHorizontalAxesMargins); checkUsedSpace(sizeShortage, "width", verticalAxes, getVerticalAxesMargins); performActionOnAxes(allAxes, "updateSize", panesCanvases); panesCanvases = shrinkCanvases(rotated, panesCanvases, getVerticalAxesMargins(verticalAxes), getHorizontalAxesMargins(horizontalAxes, getAxisMargins)); performActionOnAxes(allAxes, "updateSize", panesCanvases); horizontalAxes.forEach(shiftAxis("top", "bottom")); verticalAxes.forEach(shiftAxis("left", "right")); that.panes.forEach(function (pane) { _extend(pane.canvas, panesCanvases[pane.name]); }); } }, _getPanesParameters: function _getPanesParameters() { var that = this, panes = that.panes, i, params = []; for (i = 0; i < panes.length; i++) { if (that._getPaneBorderVisibility(i)) { params.push({ coords: panes[i].borderCoords, clipRect: that._panesClipRects.fixed[i] }); } } return params; }, _createCrosshairCursor: function _createCrosshairCursor() { var that = this, options = that._themeManager.getOptions("crosshair") || {}, index = that._displayedArgumentAxisIndex, axes = !that._isRotated() ? [[that._argumentAxes[index]], that._valueAxes] : [that._valueAxes, [that._argumentAxes[index]]], parameters = { canvas: that._getCommonCanvas(), panes: that._getPanesParameters(), axes: axes }; if (!options || !options.enabled) { return; } if (!that._crosshair) { that._crosshair = new crosshairModule.Crosshair(that._renderer, options, parameters, that._crosshairCursorGroup); } else { that._crosshair.update(options, parameters); } that._crosshair.render(); }, _getCommonCanvas: function _getCommonCanvas() { var i, canvas, commonCanvas, panes = this.panes; for (i = 0; i < panes.length; i++) { canvas = panes[i].canvas; if (!commonCanvas) { // TODO commonCanvas = _extend({}, canvas); } else { commonCanvas.right = canvas.right; commonCanvas.bottom = canvas.bottom; } } return commonCanvas; }, _createPanesBackground: function _createPanesBackground() { var that = this, defaultBackgroundColor = that._themeManager.getOptions("commonPaneSettings").backgroundColor, backgroundColor, renderer = that._renderer, rect, i, rects = []; that._panesBackgroundGroup.clear(); for (i = 0; i < that.panes.length; i++) { backgroundColor = that.panes[i].backgroundColor || defaultBackgroundColor; if (!backgroundColor || backgroundColor === "none") { rects.push(null); continue; } rect = renderer.rect(0, 0, 0, 0).attr({ fill: backgroundColor, "stroke-width": 0 }).append(that._panesBackgroundGroup); rects.push(rect); } that.panesBackground = rects; }, _fillPanesBackground: function _fillPanesBackground() { var that = this, bc; _each(that.panes, function (i, pane) { bc = pane.borderCoords; if (that.panesBackground[i] !== null) { that.panesBackground[i].attr({ x: bc.left, y: bc.top, width: bc.width, height: bc.height }); } }); }, _calcPaneBorderCoords: function _calcPaneBorderCoords(pane) { var canvas = pane.canvas, bc = pane.borderCoords = pane.borderCoords || {}; bc.left = canvas.left; bc.top = canvas.top; bc.right = canvas.width - canvas.right; bc.bottom = canvas.height - canvas.bottom; bc.width = Math.max(bc.right - bc.left, 0); bc.height = Math.max(bc.bottom - bc.top, 0); }, _drawPanesBorders: function _drawPanesBorders(panesBorderOptions) { var that = this, rotated = that._isRotated(); that._panesBorderGroup.linkRemove().clear(); _each(that.panes, function (i, pane) { var bc, borderOptions = panesBorderOptions[pane.name], segmentRectParams, attr = { fill: "none", stroke: borderOptions.color, "stroke-opacity": borderOptions.opacity, "stroke-width": borderOptions.width, dashStyle: borderOptions.dashStyle, "stroke-linecap": "square" }; that._calcPaneBorderCoords(pane, rotated); if (!borderOptions.visible) { return; } bc = pane.borderCoords; segmentRectParams = prepareSegmentRectPoints(bc.left, bc.top, bc.width, bc.height, borderOptions); that._renderer.path(segmentRectParams.points, segmentRectParams.pathType).attr(attr).append(that._panesBorderGroup); }); that._panesBorderGroup.linkAppend(); }, _createClipRect: function _createClipRect(clipArray, index, left, top, width, height) { var that = this, clipRect = clipArray[index]; if (!clipRect) { clipRect = that._renderer.clipRect(left, top, width, height); clipArray[index] = clipRect; } else { clipRect.attr({ x: left, y: top, width: width, height: height }); } }, _createClipRectsForPanes: function _createClipRectsForPanes() { var that = this, canvas = that._canvas; _each(that.panes, function (i, pane) { var needWideClipRect = false, bc = pane.borderCoords, left = bc.left, top = bc.top, width = bc.width, height = bc.height, panesClipRects = that._panesClipRects; that._createClipRect(panesClipRects.fixed, i, left, top, width, height); that._createClipRect(panesClipRects.base, i, left, top, width, height); _each(that.series, function (_, series) { if (series.pane === pane.name && (series.isFinancialSeries() || series.areErrorBarsVisible())) { needWideClipRect = true; } }); if (needWideClipRect) { if (that._isRotated()) { top = 0; height = canvas.height; } else { left = 0; width = canvas.width; } that._createClipRect(panesClipRects.wide, i, left, top, width, height); } else { panesClipRects.wide[i] = null; } }); }, _getPaneIndex: function _getPaneIndex(paneName) { var paneIndex; _each(this.panes, function (index, pane) { if (pane.name === paneName) { paneIndex = index; return false; } }); return paneIndex; }, _getPaneBorderVisibility: function _getPaneBorderVisibility(paneIndex) { var commonPaneBorderVisible = this._themeManager.getOptions("commonPaneSettings").border.visible, pane = this.panes[paneIndex] || {}, paneBorder = pane.border || {}; return "visible" in paneBorder ? paneBorder.visible : commonPaneBorderVisible; }, _getElementsClipRectID: function _getElementsClipRectID(paneName) { return this._panesClipRects.fixed[this._getPaneIndex(paneName)].id; }, _getCanvasForPane: function _getCanvasForPane(paneName) { var panes = this.panes, panesNumber = panes.length, i; for (i = 0; i < panesNumber; i++) { if (panes[i].name === paneName) { return panes[i].canvas; } } }, _transformArgument: function _transformArgument(translate, scale) { var that = this, rotated = that._isRotated(), settings, clipSettings, panesClipRects = that._panesClipRects; if (!that._transformed) { that._transformed = true; that._labelsGroup.remove(); that._resetIsReady(); _each(that.series || [], function (i, s) { s.applyClip(); }); } if (rotated) { settings = { translateY: translate, scaleY: scale }; clipSettings = { translateY: -translate / scale, scaleY: 1 / scale }; } else { settings = { translateX: translate, scaleX: scale }; clipSettings = { translateX: -translate / scale, scaleX: 1 / scale }; } applyClipSettings(panesClipRects.base, clipSettings); applyClipSettings(panesClipRects.wide, clipSettings); that._seriesGroup.attr(settings); that._scrollBar && that._scrollBar.transform(-translate, scale); }, _resetTransform: function _resetTransform() { var that = this, settings = { translateX: 0, translateY: 0, scaleX: null, scaleY: null }, panesClipRects = that._panesClipRects; applyClipSettings(panesClipRects.base, settings); applyClipSettings(panesClipRects.wide, settings); that._seriesGroup.attr(settings); _each(that.series || [], function (i, s) { s.resetClip(); }); that._transformed = false; }, _getTrackerSettings: function _getTrackerSettings() { var that = this, themeManager = that._themeManager; return _extend(this.callBase(), { chart: that, zoomingMode: themeManager.getOptions("zoomingMode"), scrollingMode: themeManager.getOptions("scrollingMode"), rotated: that._isRotated(), crosshair: that._getCrosshairOptions().enabled ? that._crosshair : null }); }, _resolveLabelOverlappingStack: function _resolveLabelOverlappingStack() { var that = this, isRotated = that._isRotated(), shiftDirection = isRotated ? function (box, length) { return { x: box.x - length, y: box.y }; } : function (box, length) { return { x: box.x, y: box.y - length }; }; _each(that._getStackPoints(), function (_, stacks) { _each(stacks, function (_, points) { overlapping.resolveLabelOverlappingInOneDirection(points, that._getCommonCanvas(), isRotated, shiftDirection); }); }); }, _getStackPoints: function _getStackPoints() { var stackPoints = {}, visibleSeries = this._getVisibleSeries(); _each(visibleSeries, function (_, singleSeries) { var points = singleSeries.getPoints(), stackName = singleSeries.getStackName() || null; _each(points, function (_, point) { var argument = point.argument; if (!stackPoints[argument]) { stackPoints[argument] = {}; } if (!stackPoints[argument][stackName]) { stackPoints[argument][stackName] = []; } stackPoints[argument][stackName].push(point); }); }); return stackPoints; }, _getCrosshairOptions: function _getCrosshairOptions() { return this._getOption("crosshair"); }, // API zoomArgument: function zoomArgument(min, max, gesturesUsed) { var that = this, bounds, zoomArg; if (!_isDefined(min) && !_isDefined(max)) { return; } if (!gesturesUsed) { that._eventTrigger("zoomStart"); } that._argumentAxes.forEach(function (axis) { zoomArg = axis.zoom(min, max, gesturesUsed); }); that._zoomMinArg = zoomArg && zoomArg.min; that._zoomMaxArg = zoomArg && zoomArg.max; that._notApplyMargins = gesturesUsed; // TODO that._recreateSizeDependentObjects(false); that._doRender({ force: true, drawTitle: false, drawLegend: false, adjustAxes: false, animate: false }); bounds = that.getVisibleArgumentBounds(); that._eventTrigger("zoomEnd", { rangeStart: bounds.minVisible, rangeEnd: bounds.maxVisible }); }, _resetZoom: function _resetZoom() { var that = this; that._zoomMinArg = that._zoomMaxArg = that._notApplyMargins = undefined; // T190927 that._argumentAxes[0].resetZoom(); that._valueAxes.forEach(function (axis) { axis.resetZoom(); }); // T602156 }, // T218011 for dashboards getVisibleArgumentBounds: function getVisibleArgumentBounds() { var translator = this._argumentAxes[0].getTranslator(), range = translator.getBusinessRange(), isDiscrete = range.axisType === "discrete", categories = range.categories; return { minVisible: isDiscrete ? range.minVisible || categories[0] : range.minVisible, maxVisible: isDiscrete ? range.maxVisible || categories[categories.length - 1] : range.maxVisible }; } }); dxChart.addPlugin(require("./chart_components/shutter_zoom")); registerComponent("dxChart", dxChart); module.exports = dxChart; ///#DEBUG module.exports._test_prepareSegmentRectPoints = function () { var original = prepareSegmentRectPoints.original || prepareSegmentRectPoints; if (arguments[0]) { prepareSegmentRectPoints = arguments[0]; } prepareSegmentRectPoints.original = original; prepareSegmentRectPoints.restore = function () { prepareSegmentRectPoints = original; }; return prepareSegmentRectPoints; }; ///#ENDDEBUG