UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

703 lines (594 loc) • 25.4 kB
"use strict"; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } var _extend = require("../../core/utils/extend").extend, inArray = require("../../core/utils/array").inArray, _each = require("../../core/utils/iterator").each, rangeCalculator = require("./helpers/range_data_calculator"), typeUtils = require("../../core/utils/type"), vizUtils = require("../core/utils"), _noop = require("../../core/utils/common").noop, _isDefined = typeUtils.isDefined, _isString = typeUtils.isString, _map = vizUtils.map, _normalizeEnum = vizUtils.normalizeEnum, math = Math, _abs = math.abs, _sqrt = math.sqrt, _max = math.max, DEFAULT_TRACKER_WIDTH = 12, DEFAULT_DURATION = 400, HIGH_ERROR = "highError", LOW_ERROR = "lowError", VARIANCE = "variance", STANDARD_DEVIATION = "stddeviation", STANDARD_ERROR = "stderror", PERCENT = "percent", FIXED = "fixed", UNDEFINED = "undefined", DISCRETE = "discrete", LOGARITHMIC = "logarithmic", DATETIME = "datetime"; exports.chart = {}; exports.polar = {}; function sum(array) { var result = 0; _each(array, function (_, value) { result += value; }); return result; } function isErrorBarTypeCorrect(type) { // TODO why UNDEFINED is here // return inArray(type, [FIXED, PERCENT, VARIANCE, STANDARD_DEVIATION, STANDARD_ERROR, UNDEFINED]) !== -1; return inArray(type, [FIXED, PERCENT, VARIANCE, STANDARD_DEVIATION, STANDARD_ERROR]) !== -1; } function variance(array, expectedValue) { return sum(_map(array, function (value) { return (value - expectedValue) * (value - expectedValue); })) / array.length; } function calculateAvgErrorBars(result, data, series) { var errorBarsOptions = series.getOptions().valueErrorBar, valueField = series.getValueFields()[0], lowValueField = errorBarsOptions.lowValueField || LOW_ERROR, highValueField = errorBarsOptions.highValueField || HIGH_ERROR; if (series.areErrorBarsVisible() && errorBarsOptions.type === undefined) { var fusionData = data.reduce(function (result, item) { if (_isDefined(item[lowValueField])) { result[0] += item[valueField] - item[lowValueField]; result[1]++; } if (_isDefined(item[highValueField])) { result[2] += item[highValueField] - item[valueField]; result[3]++; } return result; }, [0, 0, 0, 0]); if (fusionData[1]) { result[lowValueField] = result[valueField] - fusionData[0] / fusionData[1]; } if (fusionData[2]) { result[highValueField] = result[valueField] + fusionData[2] / fusionData[3]; } } return result; } function calculateSumErrorBars(result, data, series) { var errorBarsOptions = series.getOptions().valueErrorBar, lowValueField = errorBarsOptions.lowValueField || LOW_ERROR, highValueField = errorBarsOptions.highValueField || HIGH_ERROR; if (series.areErrorBarsVisible() && errorBarsOptions.type === undefined) { result[lowValueField] = 0; result[highValueField] = 0; result = data.reduce(function (result, item) { result[lowValueField] += item[lowValueField]; result[highValueField] += item[highValueField]; return result; }, result); } return result; } function getMinMaxAggregator(compare) { return function (_ref, series) { var intervalStart = _ref.intervalStart, data = _ref.data; var valueField = series.getValueFields()[0]; var targetData = data[0]; targetData = data.reduce(function (result, item) { var value = item[valueField]; if (result[valueField] === null) { result = item; } if (value !== null && compare(value, result[valueField])) { return item; } return result; }, targetData); return _extend({}, targetData, _defineProperty({}, series.getArgumentField(), intervalStart)); }; } var baseScatterMethods = { _defaultDuration: DEFAULT_DURATION, _defaultTrackerWidth: DEFAULT_TRACKER_WIDTH, _applyStyle: _noop, _updateOptions: _noop, _parseStyle: _noop, _prepareSegment: _noop, _drawSegment: _noop, _appendInGroup: function _appendInGroup() { this._group.append(this._extGroups.seriesGroup); }, _createLegendState: function _createLegendState(styleOptions, defaultColor) { return { fill: styleOptions.color || defaultColor, hatching: styleOptions.hatching ? _extend({}, styleOptions.hatching, { direction: "right" }) : undefined }; }, _applyElementsClipRect: function _applyElementsClipRect(settings) { settings["clip-path"] = this._paneClipRectID; }, _applyMarkerClipRect: function _applyMarkerClipRect(settings) { settings["clip-path"] = this._forceClipping ? this._paneClipRectID : null; }, _createGroup: function _createGroup(groupName, parent, target, settings) { var group = parent[groupName] = parent[groupName] || this._renderer.g(); target && group.append(target); settings && group.attr(settings); }, _applyClearingSettings: function _applyClearingSettings(settings) { settings.opacity = null; settings.scale = null; if (this._options.rotated) { settings.translateX = null; } else { settings.translateY = null; } }, _createGroups: function _createGroups() { var that = this; that._createGroup("_markersGroup", that, that._group); that._createGroup("_labelsGroup", that); }, _setMarkerGroupSettings: function _setMarkerGroupSettings() { var that = this, settings = that._createPointStyles(that._getMarkerGroupOptions()).normal; settings["class"] = "dxc-markers"; settings.opacity = 1; // T172577 that._applyMarkerClipRect(settings); that._markersGroup.attr(settings); }, getVisibleArea: function getVisibleArea() { return this._visibleArea; }, areErrorBarsVisible: function areErrorBarsVisible() { var errorBarOptions = this._options.valueErrorBar; return errorBarOptions && this._errorBarsEnabled() && errorBarOptions.displayMode !== "none" && (isErrorBarTypeCorrect(_normalizeEnum(errorBarOptions.type)) || _isDefined(errorBarOptions.lowValueField) || _isDefined(errorBarOptions.highValueField)); }, _createErrorBarGroup: function _createErrorBarGroup(animationEnabled) { var that = this, errorBarOptions = that._options.valueErrorBar, settings; if (that.areErrorBarsVisible()) { settings = { "class": "dxc-error-bars", stroke: errorBarOptions.color, 'stroke-width': errorBarOptions.lineWidth, opacity: animationEnabled ? 0.001 : errorBarOptions.opacity || 1, "stroke-linecap": "square", sharp: true, "clip-path": that._forceClipping ? that._paneClipRectID : that._widePaneClipRectID }; that._createGroup("_errorBarGroup", that, that._group, settings); } }, _setGroupsSettings: function _setGroupsSettings(animationEnabled) { var that = this; that._setMarkerGroupSettings(); that._setLabelGroupSettings(animationEnabled); that._createErrorBarGroup(animationEnabled); }, _getCreatingPointOptions: function _getCreatingPointOptions() { var that = this, defaultPointOptions, creatingPointOptions = that._predefinedPointOptions, normalStyle; if (!creatingPointOptions) { defaultPointOptions = that._getPointOptions(); that._predefinedPointOptions = creatingPointOptions = _extend(true, { styles: {} }, defaultPointOptions); normalStyle = defaultPointOptions.styles && defaultPointOptions.styles.normal || {}; creatingPointOptions.styles = creatingPointOptions.styles || {}; creatingPointOptions.styles.normal = { "stroke-width": normalStyle["stroke-width"], r: normalStyle.r, opacity: normalStyle.opacity }; } return creatingPointOptions; }, _getPointOptions: function _getPointOptions() { return this._parsePointOptions(this._preparePointOptions(), this._options.label); }, _getOptionsForPoint: function _getOptionsForPoint() { return this._options.point; }, _parsePointStyle: function _parsePointStyle(style, defaultColor, defaultBorderColor, defaultSize) { var border = style.border || {}, sizeValue = style.size !== undefined ? style.size : defaultSize; return { fill: style.color || defaultColor, stroke: border.color || defaultBorderColor, "stroke-width": border.visible ? border.width : 0, r: sizeValue / 2 + (border.visible && sizeValue !== 0 ? ~~(border.width / 2) || 0 : 0) }; }, _createPointStyles: function _createPointStyles(pointOptions) { var that = this, mainPointColor = pointOptions.color || that._options.mainSeriesColor, containerColor = that._options.containerBackgroundColor, normalStyle = that._parsePointStyle(pointOptions, mainPointColor, mainPointColor); normalStyle.visibility = pointOptions.visible ? "visible" : "hidden"; return { normal: normalStyle, hover: that._parsePointStyle(pointOptions.hoverStyle, containerColor, mainPointColor, pointOptions.size), selection: that._parsePointStyle(pointOptions.selectionStyle, containerColor, mainPointColor, pointOptions.size) }; }, _checkData: function _checkData(data) { return _isDefined(data.argument) && data.value !== undefined && data.value === data.value; }, getErrorBarRangeCorrector: function getErrorBarRangeCorrector() { var mode, func; if (this.areErrorBarsVisible()) { mode = _normalizeEnum(this._options.valueErrorBar.displayMode); func = function func(point) { var lowError = point.lowError, highError = point.highError; switch (mode) { case "low": return [lowError]; case "high": return [highError]; case "none": return []; default: return [lowError, highError]; } }; } return func; }, getValueRangeInitialValue: function getValueRangeInitialValue() { return undefined; }, _getRangeData: function _getRangeData() { return rangeCalculator.getRangeData(this); }, _getPointDataSelector: function _getPointDataSelector() { var valueField = this.getValueFields()[0]; var argumentField = this.getArgumentField(); var tagField = this.getTagField(); var areErrorBarsVisible = this.areErrorBarsVisible(); var lowValueField = void 0, highValueField = void 0; if (areErrorBarsVisible) { var errorBarOptions = this._options.valueErrorBar; lowValueField = errorBarOptions.lowValueField || LOW_ERROR; highValueField = errorBarOptions.highValueField || HIGH_ERROR; } return function (data) { var pointData = { value: data[valueField], argument: data[argumentField], tag: data[tagField], data: data }; if (areErrorBarsVisible) { pointData.lowError = data[lowValueField]; pointData.highError = data[highValueField]; } return pointData; }; }, _errorBarsEnabled: function _errorBarsEnabled() { return this.valueAxisType !== DISCRETE && this.valueAxisType !== LOGARITHMIC && this.valueType !== DATETIME; }, _drawPoint: function _drawPoint(options) { var point = options.point; if (point.isInVisibleArea()) { point.clearVisibility(); point.draw(this._renderer, options.groups, options.hasAnimation, options.firstDrawing); this._drawnPoints.push(point); } else { point.setInvisibility(); } }, _animateComplete: function _animateComplete() { var that = this, animationSettings = { duration: that._defaultDuration }; that._labelsGroup && that._labelsGroup.animate({ opacity: 1 }, animationSettings); that._errorBarGroup && that._errorBarGroup.animate({ opacity: that._options.valueErrorBar.opacity || 1 }, animationSettings); }, _animate: function _animate() { var that = this, lastPointIndex = that._drawnPoints.length - 1; _each(that._drawnPoints || [], function (i, p) { p.animate(i === lastPointIndex ? function () { that._animateComplete(); } : undefined, { translateX: p.x, translateY: p.y }); }); }, _defaultAggregator: "avg", _aggregators: { avg: function avg(_ref2, series) { var _calculateAvgErrorBar; var data = _ref2.data, intervalStart = _ref2.intervalStart; if (!data.length) { return; } var valueField = series.getValueFields()[0]; var aggregationResult = data.reduce(function (result, item) { var value = item[valueField]; if (_isDefined(value)) { result[0] += value; result[1]++; } else if (value === null) { result[2]++; } return result; }, [0, 0, 0]); return calculateAvgErrorBars((_calculateAvgErrorBar = {}, _defineProperty(_calculateAvgErrorBar, valueField, aggregationResult[2] === data.length ? null : aggregationResult[0] / aggregationResult[1]), _defineProperty(_calculateAvgErrorBar, series.getArgumentField(), intervalStart), _calculateAvgErrorBar), data, series); }, sum: function sum(_ref3, series) { var _calculateSumErrorBar; var intervalStart = _ref3.intervalStart, data = _ref3.data; if (!data.length) { return; } var valueField = series.getValueFields()[0]; var aggregationResult = data.reduce(function (result, item) { var value = item[valueField]; if (value !== undefined) { result[0] += value; } if (value === null) { result[1]++; } else if (value === undefined) { result[2]++; } return result; }, [0, 0, 0]); var value = aggregationResult[0]; if (aggregationResult[1] === data.length) { value = null; } if (aggregationResult[2] === data.length) { return; } return calculateSumErrorBars((_calculateSumErrorBar = {}, _defineProperty(_calculateSumErrorBar, valueField, value), _defineProperty(_calculateSumErrorBar, series.getArgumentField(), intervalStart), _calculateSumErrorBar), data, series); }, count: function count(_ref4, series) { var _ref5; var data = _ref4.data, intervalStart = _ref4.intervalStart; var valueField = series.getValueFields()[0]; return _ref5 = {}, _defineProperty(_ref5, series.getArgumentField(), intervalStart), _defineProperty(_ref5, valueField, data.filter(function (i) { return i[valueField] !== undefined; }).length), _ref5; }, min: getMinMaxAggregator(function (a, b) { return a < b; }), max: getMinMaxAggregator(function (a, b) { return a > b; }) }, _endUpdateData: function _endUpdateData() { delete this._predefinedPointOptions; }, getArgumentField: function getArgumentField() { return this._options.argumentField || "arg"; }, getValueFields: function getValueFields() { var options = this._options, errorBarsOptions = options.valueErrorBar, valueFields = [options.valueField || "val"], lowValueField, highValueField; if (errorBarsOptions) { lowValueField = errorBarsOptions.lowValueField; highValueField = errorBarsOptions.highValueField; _isString(lowValueField) && valueFields.push(lowValueField); _isString(highValueField) && valueFields.push(highValueField); } return valueFields; }, _calculateErrorBars: function _calculateErrorBars(data) { if (!this.areErrorBarsVisible()) { return; } var that = this, options = that._options, errorBarsOptions = options.valueErrorBar, errorBarType = _normalizeEnum(errorBarsOptions.type), floatErrorValue = parseFloat(errorBarsOptions.value), valueField = that.getValueFields()[0], value, lowValueField = errorBarsOptions.lowValueField || LOW_ERROR, highValueField = errorBarsOptions.highValueField || HIGH_ERROR, valueArray, valueArrayLength, meanValue, processDataItem, addSubError = function addSubError(_i, item) { value = item.value; item.lowError = value - floatErrorValue; item.highError = value + floatErrorValue; }; switch (errorBarType) { case FIXED: processDataItem = addSubError; break; case PERCENT: processDataItem = function processDataItem(_, item) { value = item.value; var error = value * floatErrorValue / 100; item.lowError = value - error; item.highError = value + error; }; break; case UNDEFINED: // TODO: rework this processDataItem = function processDataItem(_, item) { item.lowError = item.data[lowValueField]; item.highError = item.data[highValueField]; }; break; default: valueArray = _map(data, function (item) { return _isDefined(item.data[valueField]) ? item.data[valueField] : null; }); valueArrayLength = valueArray.length; floatErrorValue = floatErrorValue || 1; switch (errorBarType) { case VARIANCE: floatErrorValue = variance(valueArray, sum(valueArray) / valueArrayLength) * floatErrorValue; processDataItem = addSubError; break; case STANDARD_DEVIATION: meanValue = sum(valueArray) / valueArrayLength; floatErrorValue = _sqrt(variance(valueArray, meanValue)) * floatErrorValue; processDataItem = function processDataItem(_, item) { item.lowError = meanValue - floatErrorValue; item.highError = meanValue + floatErrorValue; }; break; case STANDARD_ERROR: floatErrorValue = _sqrt(variance(valueArray, sum(valueArray) / valueArrayLength) / valueArrayLength) * floatErrorValue; processDataItem = addSubError; break; } } processDataItem && _each(data, processDataItem); }, _patchMarginOptions: function _patchMarginOptions(options) { var pointOptions = this._getCreatingPointOptions(), styles = pointOptions.styles, maxSize = [styles.normal, styles.hover, styles.selection].reduce(function (max, style) { return _max(max, style.r * 2 + style["stroke-width"]); }, 0); options.size = pointOptions.visible ? maxSize : 0; options.sizePointNormalState = pointOptions.visible ? styles.normal.r * 2 + styles.normal["stroke-width"] : 2; return options; } }; exports.chart = _extend({}, baseScatterMethods, { drawTrackers: function drawTrackers() { var that = this, trackers, trackersGroup, segments = that._segments || [], rotated = that._options.rotated, cat = []; if (!that.isVisible()) { return; } if (segments.length) { trackers = that._trackers = that._trackers || []; trackersGroup = that._trackersGroup = (that._trackersGroup || that._renderer.g().attr({ fill: "gray", opacity: 0.001, stroke: "gray", "class": "dxc-trackers" })).attr({ "clip-path": this._paneClipRectID || null }).append(that._group); _each(segments, function (i, segment) { if (!trackers[i]) { trackers[i] = that._drawTrackerElement(segment).data({ "chart-data-series": that }).append(trackersGroup); } else { that._updateTrackerElement(segment, trackers[i]); } }); } that._trackersTranslator = cat; _each(that.getVisiblePoints(), function (_, p) { var pointCoord = parseInt(rotated ? p.vy : p.vx); if (!cat[pointCoord]) { cat[pointCoord] = p; } else { Array.isArray(cat[pointCoord]) ? cat[pointCoord].push(p) : cat[pointCoord] = [cat[pointCoord], p]; } }); }, getNeighborPoint: function getNeighborPoint(x, y) { var pCoord = this._options.rotated ? y : x, nCoord = pCoord, cat = this._trackersTranslator, point = null, minDistance, oppositeCoord = this._options.rotated ? x : y, oppositeCoordName = this._options.rotated ? "vx" : "vy"; if (this.isVisible() && cat) { point = cat[pCoord]; do { point = cat[nCoord] || cat[pCoord]; pCoord--; nCoord++; } while ((pCoord >= 0 || nCoord < cat.length) && !point); if (Array.isArray(point)) { minDistance = _abs(point[0][oppositeCoordName] - oppositeCoord); _each(point, function (i, p) { var distance = _abs(p[oppositeCoordName] - oppositeCoord); if (minDistance >= distance) { minDistance = distance; point = p; } }); } } return point; }, _applyVisibleArea: function _applyVisibleArea() { var that = this, rotated = that._options.rotated, visibleX = (rotated ? that.getValueAxis() : that.getArgumentAxis()).getTranslator().getCanvasVisibleArea(), visibleY = (rotated ? that.getArgumentAxis() : that.getValueAxis()).getTranslator().getCanvasVisibleArea(); that._visibleArea = { minX: visibleX.min, maxX: visibleX.max, minY: visibleY.min, maxY: visibleY.max }; } }); exports.polar = _extend({}, baseScatterMethods, { drawTrackers: function drawTrackers() { exports.chart.drawTrackers.call(this); var cat = this._trackersTranslator, index; if (!this.isVisible()) { return; } _each(cat, function (i, category) { if (category) { index = i; return false; } }); cat[index + 360] = cat[index]; }, getNeighborPoint: function getNeighborPoint(x, y) { var pos = vizUtils.convertXYToPolar(this.getValueAxis().getCenter(), x, y); return exports.chart.getNeighborPoint.call(this, pos.phi, pos.r); }, _applyVisibleArea: function _applyVisibleArea() { var that = this, canvas = that.getValueAxis().getCanvas(); that._visibleArea = { minX: canvas.left, maxX: canvas.width - canvas.right, minY: canvas.top, maxY: canvas.height - canvas.bottom }; } });