UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

658 lines (562 loc) • 24.3 kB
"use strict"; var extend = require("../../../core/utils/extend").extend, each = require("../../../core/utils/iterator").each, noop = require("../../../core/utils/common").noop, windowUtils = require("../../../core/utils/window"), window = windowUtils.getWindow(), labelModule = require("./label"), _extend = extend, _isDefined = require("../../../core/utils/type").isDefined, _normalizeEnum = require("../../core/utils").normalizeEnum, _math = Math, _round = _math.round, _floor = _math.floor, _ceil = _math.ceil, DEFAULT_IMAGE_WIDTH = 20, DEFAULT_IMAGE_HEIGHT = 20, LABEL_OFFSET = 10, CANVAS_POSITION_DEFAULT = "canvas_position_default"; function getSquareMarkerCoords(radius) { return [-radius, -radius, radius, -radius, radius, radius, -radius, radius, -radius, -radius]; } function getPolygonMarkerCoords(radius) { var r = _ceil(radius); // T100386 return [-r, 0, 0, -r, r, 0, 0, r, -r, 0]; } function getCrossMarkerCoords(radius) { var r = _ceil(radius), // T100386 floorHalfRadius = _floor(r / 2), ceilHalfRadius = _ceil(r / 2); return [-r, -floorHalfRadius, -floorHalfRadius, -r, 0, -ceilHalfRadius, floorHalfRadius, -r, r, -floorHalfRadius, ceilHalfRadius, 0, r, floorHalfRadius, floorHalfRadius, r, 0, ceilHalfRadius, -floorHalfRadius, r, -r, floorHalfRadius, -ceilHalfRadius, 0]; } function getTriangleDownMarkerCoords(radius) { return [-radius, -radius, radius, -radius, 0, radius, -radius, -radius]; } function getTriangleUpMarkerCoords(radius) { return [-radius, radius, radius, radius, 0, -radius, -radius, radius]; } module.exports = { deleteLabel: function deleteLabel() { this._label.dispose(); this._label = null; }, _hasGraphic: function _hasGraphic() { return this.graphic; }, clearVisibility: function clearVisibility() { var that = this, graphic = that.graphic; if (graphic && graphic.attr("visibility")) { graphic.attr({ visibility: null }); } }, isVisible: function isVisible() { return this.inVisibleArea && this.series.isVisible(); }, setInvisibility: function setInvisibility() { var that = this, graphic = that.graphic; if (graphic && graphic.attr("visibility") !== "hidden") { graphic.attr({ visibility: "hidden" }); } that._errorBar && that._errorBar.attr({ visibility: "hidden" }); that._label.draw(false); }, clearMarker: function clearMarker() { var graphic = this.graphic; graphic && graphic.attr(this._emptySettings); }, _createLabel: function _createLabel() { this._label = new labelModule.Label({ renderer: this.series._renderer, labelsGroup: this.series._labelsGroup, point: this }); }, _updateLabelData: function _updateLabelData() { this._label.setData(this._getLabelFormatObject()); }, _updateLabelOptions: function _updateLabelOptions() { !this._label && this._createLabel(); this._label.setOptions(this._options.label); }, _checkImage: function _checkImage(image) { return _isDefined(image) && (typeof image === "string" || _isDefined(image.url)); }, _fillStyle: function _fillStyle() { this._styles = this._options.styles; }, _checkSymbol: function _checkSymbol(oldOptions, newOptions) { var oldSymbol = oldOptions.symbol, newSymbol = newOptions.symbol, symbolChanged = oldSymbol === "circle" && newSymbol !== "circle" || oldSymbol !== "circle" && newSymbol === "circle", imageChanged = this._checkImage(oldOptions.image) !== this._checkImage(newOptions.image); return !!(symbolChanged || imageChanged); }, _populatePointShape: function _populatePointShape(symbol, radius) { switch (symbol) { case "square": return getSquareMarkerCoords(radius); case "polygon": return getPolygonMarkerCoords(radius); case "triangle": case "triangleDown": return getTriangleDownMarkerCoords(radius); case "triangleUp": return getTriangleUpMarkerCoords(radius); case "cross": return getCrossMarkerCoords(radius); } }, hasCoords: function hasCoords() { return this.x !== null && this.y !== null; }, correctValue: function correctValue(correction) { var that = this; if (that.hasValue()) { that.value = that.initialValue + correction; that.minValue = correction; } }, resetCorrection: function resetCorrection() { this.value = this.initialValue; this.minValue = CANVAS_POSITION_DEFAULT; }, resetValue: function resetValue() { var that = this; if (that.hasValue()) { that.value = that.initialValue = 0; that.minValue = 0; that._label.setDataField("value", that.value); } }, _getTranslates: function _getTranslates(animationEnabled) { var translateX = this.x, translateY = this.y; if (animationEnabled) { if (this._options.rotated) { translateX = this.defaultX; } else { translateY = this.defaultY; } } return { x: translateX, y: translateY }; }, _createImageMarker: function _createImageMarker(renderer, settings, options) { var width = options.width || DEFAULT_IMAGE_WIDTH, height = options.height || DEFAULT_IMAGE_HEIGHT; return renderer.image(-_round(width * 0.5), -_round(height * 0.5), width, height, options.url ? options.url.toString() : options.toString(), "center").attr({ translateX: settings.translateX, translateY: settings.translateY, visibility: settings.visibility }); }, _createSymbolMarker: function _createSymbolMarker(renderer, pointSettings) { var marker, symbol = this._options.symbol; if (symbol === "circle") { delete pointSettings.points; marker = renderer.circle().attr(pointSettings); } else if (symbol === "square" || symbol === "polygon" || symbol === "triangle" || symbol === "triangleDown" || symbol === "triangleUp" || symbol === "cross") { marker = renderer.path([], "area").attr(pointSettings).sharp(); } return marker; }, _createMarker: function _createMarker(renderer, group, image, settings) { var that = this, marker = that._checkImage(image) ? that._createImageMarker(renderer, settings, image) : that._createSymbolMarker(renderer, settings); if (marker) { marker.data({ "chart-data-point": that }).append(group); } return marker; }, _getSymbolBBox: function _getSymbolBBox(x, y, r) { return { x: x - r, y: y - r, width: r * 2, height: r * 2 }; }, _getImageBBox: function _getImageBBox(x, y) { var image = this._options.image, width = image.width || DEFAULT_IMAGE_WIDTH, height = image.height || DEFAULT_IMAGE_HEIGHT; return { x: x - _round(width / 2), y: y - _round(height / 2), width: width, height: height }; }, _getGraphicBBox: function _getGraphicBBox() { var that = this, options = that._options, x = that.x, y = that.y, bBox; if (options.visible) { bBox = that._checkImage(options.image) ? that._getImageBBox(x, y) : that._getSymbolBBox(x, y, options.styles.normal.r); } else { bBox = { x: x, y: y, width: 0, height: 0 }; } return bBox; }, hideInsideLabel: noop, _getShiftLabelCoords: function _getShiftLabelCoords(label) { var coord = this._addLabelAlignmentAndOffset(label, this._getLabelCoords(label)); return this._checkLabelPosition(label, coord); }, _drawLabel: function _drawLabel() { var that = this, customVisibility = that._getCustomLabelVisibility(), label = that._label, isVisible = that._showForZeroValues() && that.hasValue() && customVisibility !== false && (that.series.getLabelVisibility() || customVisibility); label.draw(!!isVisible); }, correctLabelPosition: function correctLabelPosition(label) { var that = this, coord = that._getShiftLabelCoords(label); if (!that.hideInsideLabel(label, coord)) { label.setFigureToDrawConnector(that._getLabelConnector(label.pointPosition)); label.shift(_round(coord.x), _round(coord.y)); } }, _showForZeroValues: function _showForZeroValues() { return true; }, _getLabelConnector: function _getLabelConnector(pointPosition) { var bBox = this._getGraphicBBox(pointPosition), w2 = bBox.width / 2, h2 = bBox.height / 2; // This is to make label connector end at the center of point; "width" and "height" are required by the path building algorithm // TODO: When path building algorithm is updated remove "width" and "height" return { x: bBox.x + w2, y: bBox.y + h2, r: this._options.visible ? Math.max(w2, h2) : 0 }; }, _getPositionFromLocation: function _getPositionFromLocation() { return { x: this.x, y: this.y }; }, _isPointInVisibleArea: function _isPointInVisibleArea(visibleArea, graphicBBox) { return visibleArea.minX <= graphicBBox.x + graphicBBox.width && visibleArea.maxX >= graphicBBox.x && visibleArea.minY <= graphicBBox.y + graphicBBox.height && visibleArea.maxY >= graphicBBox.y; }, _checkLabelPosition: function _checkLabelPosition(label, coord) { var that = this, visibleArea = that._getVisibleArea(), labelBBox = label.getBoundingRect(), graphicBBox = that._getGraphicBBox(label.pointPosition), offset = LABEL_OFFSET; if (that._isPointInVisibleArea(visibleArea, graphicBBox)) { if (!that._options.rotated) { if (visibleArea.minX > coord.x) { coord.x = visibleArea.minX; } if (visibleArea.maxX < coord.x + labelBBox.width) { coord.x = visibleArea.maxX - labelBBox.width; } if (visibleArea.minY > coord.y) { coord.y = graphicBBox.y + graphicBBox.height + offset; } if (visibleArea.maxY < coord.y + labelBBox.height) { coord.y = graphicBBox.y - labelBBox.height - offset; } } else { if (visibleArea.minX > coord.x) { coord.x = graphicBBox.x + graphicBBox.width + offset; } if (visibleArea.maxX < coord.x + labelBBox.width) { coord.x = graphicBBox.x - offset - labelBBox.width; } if (visibleArea.minY > coord.y) { coord.y = visibleArea.minY; } if (visibleArea.maxY < coord.y + labelBBox.height) { coord.y = visibleArea.maxY - labelBBox.height; } } } return coord; }, _addLabelAlignmentAndOffset: function _addLabelAlignmentAndOffset(label, coord) { var labelBBox = label.getBoundingRect(), labelOptions = label.getLayoutOptions(); if (!this._options.rotated) { if (labelOptions.alignment === "left") { coord.x += labelBBox.width / 2; } else if (labelOptions.alignment === "right") { coord.x -= labelBBox.width / 2; } } coord.x += labelOptions.horizontalOffset; coord.y += labelOptions.verticalOffset; return coord; }, _getLabelCoords: function _getLabelCoords(label) { return this._getLabelCoordOfPosition(label, this._getLabelPosition(label.pointPosition)); }, _getLabelCoordOfPosition: function _getLabelCoordOfPosition(label, position) { var that = this, labelBBox = label.getBoundingRect(), graphicBBox = that._getGraphicBBox(label.pointPosition), offset = LABEL_OFFSET, centerY = graphicBBox.height / 2 - labelBBox.height / 2, centerX = graphicBBox.width / 2 - labelBBox.width / 2, x = graphicBBox.x, y = graphicBBox.y; switch (position) { case "left": x -= labelBBox.width + offset; y += centerY; break; case "right": x += graphicBBox.width + offset; y += centerY; break; case "top": x += centerX; y -= labelBBox.height + offset; break; case "bottom": x += centerX; y += graphicBBox.height + offset; break; case "inside": x += centerX; y += centerY; break; } return { x: x, y: y }; }, _drawMarker: function _drawMarker(renderer, group, animationEnabled) { var that = this, options = that._options, translates = that._getTranslates(animationEnabled), style = that._getStyle(); that.graphic = that._createMarker(renderer, group, options.image, _extend({ translateX: translates.x, translateY: translates.y, points: that._populatePointShape(options.symbol, style.r) }, style)); }, _getErrorBarSettings: function _getErrorBarSettings() { return { visibility: "visible" }; }, _drawErrorBar: function _drawErrorBar(renderer, group) { if (!this._options.errorBars) { return; } var that = this, options = that._options, errorBarOptions = options.errorBars, points = [], settings, pos = that._errorBarPos, high = that._highErrorCoord, low = that._lowErrorCoord, displayMode = _normalizeEnum(errorBarOptions.displayMode), isHighDisplayMode = displayMode === "high", isLowDisplayMode = displayMode === "low", edgeLength = _floor(parseInt(errorBarOptions.edgeLength) / 2), highErrorOnly = (isHighDisplayMode || !_isDefined(low)) && _isDefined(high) && !isLowDisplayMode, lowErrorOnly = (isLowDisplayMode || !_isDefined(high)) && _isDefined(low) && !isHighDisplayMode; highErrorOnly && (low = that._baseErrorBarPos); lowErrorOnly && (high = that._baseErrorBarPos); if (displayMode !== "none" && _isDefined(high) && _isDefined(low) && _isDefined(pos)) { !lowErrorOnly && points.push([pos - edgeLength, high, pos + edgeLength, high]); points.push([pos, high, pos, low]); !highErrorOnly && points.push([pos + edgeLength, low, pos - edgeLength, low]); options.rotated && each(points, function (_, p) { p.reverse(); }); settings = that._getErrorBarSettings(errorBarOptions); if (!that._errorBar) { that._errorBar = renderer.path(points, "line").attr(settings).append(group); } else { settings.points = points; that._errorBar.attr(settings); } } else { that._errorBar && that._errorBar.attr({ visibility: "hidden" }); } }, getTooltipParams: function getTooltipParams() { var that = this, graphic = that.graphic; return { x: that.x, y: that.y, offset: graphic ? graphic.getBBox().height / 2 : 0 }; }, setPercentValue: function setPercentValue(absTotal, total, leftHoleTotal, rightHoleTotal) { var that = this, valuePercent = that.value / absTotal || 0, minValuePercent = that.minValue / absTotal || 0, percent = valuePercent - minValuePercent; that._label.setDataField("percent", percent); that._label.setDataField("total", total); if (that.series.isFullStackedSeries() && that.hasValue()) { if (that.leftHole) { that.leftHole /= absTotal - leftHoleTotal; that.minLeftHole /= absTotal - leftHoleTotal; } if (that.rightHole) { that.rightHole /= absTotal - rightHoleTotal; that.minRightHole /= absTotal - rightHoleTotal; } that.value = valuePercent; that.minValue = !minValuePercent ? that.minValue : minValuePercent; } }, _storeTrackerR: function _storeTrackerR() { var that = this, navigator = window.navigator, r = that._options.styles.normal.r, minTrackerSize; ///#DEBUG navigator = that.__debug_navigator || navigator; that.__debug_browserNavigator = navigator; ///#ENDDEBUG minTrackerSize = windowUtils.hasProperty("ontouchstart") || navigator.msPointerEnabled && navigator.msMaxTouchPoints || navigator.pointerEnabled && navigator.maxTouchPoints ? 20 : 6; that._options.trackerR = r < minTrackerSize ? minTrackerSize : r; return that._options.trackerR; }, _translateErrorBars: function _translateErrorBars() { var that = this, options = that._options, rotated = options.rotated, errorBars = options.errorBars, translator = that._getValTranslator(); if (!errorBars) { return; } _isDefined(that.lowError) && (that._lowErrorCoord = translator.translate(that.lowError)); _isDefined(that.highError) && (that._highErrorCoord = translator.translate(that.highError)); that._errorBarPos = _floor(rotated ? that.vy : that.vx); that._baseErrorBarPos = errorBars.type === "stdDeviation" ? that._lowErrorCoord + (that._highErrorCoord - that._lowErrorCoord) / 2 : rotated ? that.vx : that.vy; }, _translate: function _translate() { var that = this, valTranslator = that._getValTranslator(), argTranslator = that._getArgTranslator(); if (that._options.rotated) { that.vx = that.x = valTranslator.translate(that.value); that.vy = that.y = argTranslator.translate(that.argument); that.minX = valTranslator.translate(that.minValue); that.defaultX = valTranslator.translate(CANVAS_POSITION_DEFAULT); } else { that.vy = that.y = valTranslator.translate(that.value); that.vx = that.x = argTranslator.translate(that.argument); that.minY = valTranslator.translate(that.minValue); that.defaultY = valTranslator.translate(CANVAS_POSITION_DEFAULT); } that._translateErrorBars(); that._calculateVisibility(that.x, that.y); }, _updateData: function _updateData(data) { var that = this; that.value = that.initialValue = that.originalValue = data.value; that.minValue = that.initialMinValue = that.originalMinValue = _isDefined(data.minValue) ? data.minValue : CANVAS_POSITION_DEFAULT; }, _getImageSettings: function _getImageSettings(image) { return { href: image.url || image.toString(), width: image.width || DEFAULT_IMAGE_WIDTH, height: image.height || DEFAULT_IMAGE_HEIGHT }; }, getCrosshairData: function getCrosshairData() { var that = this, r = that._options.rotated, value = that.value, argument = that.argument; return { x: that.vx, y: that.vy, xValue: r ? value : argument, yValue: r ? argument : value, axis: that.series.axis }; }, getPointRadius: function getPointRadius() { var style = this._getStyle(), options = this._options, r = style.r, extraSpace, symbol = options.symbol, isSquare = symbol === "square", isTriangle = symbol === "triangle" || symbol === "triangleDown" || symbol === "triangleUp"; if (options.visible && !options.image && r) { extraSpace = style["stroke-width"] / 2; return (isSquare || isTriangle ? 1.4 * r : r) + extraSpace; } return 0; }, _updateMarker: function _updateMarker(animationEnabled, style) { var that = this, options = that._options, settings, image = options.image, visibility = !that.isVisible() ? { visibility: "hidden" } : {}; if (that._checkImage(image)) { settings = _extend({}, { visibility: style.visibility }, visibility, that._getImageSettings(image)); } else { settings = _extend({}, style, visibility, { points: that._populatePointShape(options.symbol, style.r) }); } if (!animationEnabled) { settings.translateX = that.x; settings.translateY = that.y; } that.graphic.attr(settings).sharp(); }, _getLabelFormatObject: function _getLabelFormatObject() { var that = this; return { argument: that.initialArgument, value: that.initialValue, originalArgument: that.originalArgument, originalValue: that.originalValue, seriesName: that.series.name, lowErrorValue: that.lowError, highErrorValue: that.highError, point: that }; }, _getLabelPosition: function _getLabelPosition() { var rotated = this._options.rotated; if (this.initialValue > 0) { return rotated ? "right" : "top"; } else { return rotated ? "left" : "bottom"; } }, _getFormatObject: function _getFormatObject(tooltip) { var that = this, labelFormatObject = that._label.getData(); return _extend({}, labelFormatObject, { argumentText: tooltip.formatValue(that.initialArgument, "argument"), valueText: tooltip.formatValue(that.initialValue) }, _isDefined(labelFormatObject.percent) ? { percentText: tooltip.formatValue(labelFormatObject.percent, "percent") } : {}, _isDefined(labelFormatObject.total) ? { totalText: tooltip.formatValue(labelFormatObject.total) } : {}); }, _getMarkerVisibility: function _getMarkerVisibility() { return this._options.visible; }, coordsIn: function coordsIn(x, y) { var trackerRadius = this._storeTrackerR(); return x >= this.x - trackerRadius && x <= this.x + trackerRadius && y >= this.y - trackerRadius && y <= this.y + trackerRadius; }, getMinValue: function getMinValue() { var errorBarOptions = this._options.errorBars; if (errorBarOptions) { var displayMode = errorBarOptions.displayMode, lowValue = displayMode === "high" ? this.value : this.lowError, highValue = displayMode === "low" ? this.value : this.highError; return lowValue < highValue ? lowValue : highValue; } else { return this.value; } }, getMaxValue: function getMaxValue() { var errorBarOptions = this._options.errorBars; if (errorBarOptions) { var displayMode = errorBarOptions.displayMode, lowValue = displayMode === "high" ? this.value : this.lowError, highValue = displayMode === "low" ? this.value : this.highError; return lowValue > highValue ? lowValue : highValue; } else { return this.value; } } };