UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

458 lines (456 loc) • 16.4 kB
/** * DevExtreme (esm/viz/gauges/base_indicators.js) * Version: 24.2.6 * Build date: Mon Mar 17 2025 * * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import { noop } from "../../core/utils/common"; import { each } from "../../core/utils/iterator"; const _isFinite = isFinite; const _Number = Number; const _round = Math.round; import { formatValue, getSampleText } from "./base_gauge"; const _formatValue = formatValue; const _getSampleText = getSampleText; import { patchFontOptions as _patchFontOptions, extractColor } from "../core/utils"; import { extend } from "../../core/utils/extend"; import Class from "../../core/class"; export const BaseElement = Class.inherit({ ctor: function(parameters) { const that = this; each(parameters, (function(name, value) { that["_" + name] = value })); that._init() }, dispose: function() { const that = this; that._dispose(); each(that, (function(name) { that[name] = null })); return that }, getOffset: function() { return _Number(this._options.offset) || 0 } }); export const BaseIndicator = BaseElement.inherit({ _init: function() { this._rootElement = this._createRoot().linkOn(this._owner, { name: "value-indicator", after: "core" }); this._trackerElement = this._createTracker() }, _dispose: function() { this._rootElement.linkOff() }, _setupAnimation: function() { const that = this; if (that._options.animation) { that._animation = { step: function(pos) { that._actualValue = that._animation.start + that._animation.delta * pos; that._actualPosition = that._translator.translate(that._actualValue); that._move() }, duration: that._options.animation.duration > 0 ? _Number(that._options.animation.duration) : 0, easing: that._options.animation.easing } } }, _runAnimation: function(value) { const animation = this._animation; animation.start = this._actualValue; animation.delta = value - this._actualValue; this._rootElement.animate({ _: 0 }, { step: animation.step, duration: animation.duration, easing: animation.easing }) }, _createRoot: function() { return this._renderer.g().attr({ class: this._className }) }, _createTracker: function() { return this._renderer.path([], "area") }, _getTrackerSettings: noop, clean: function() { this._animation && this._rootElement.stopAnimation(); this._rootElement.linkRemove().clear(); this._clear(); this._tracker.detach(this._trackerElement); this._options = this.enabled = this._animation = null; return this }, render: function(options) { const that = this; that.type = options.type; that._options = options; that._actualValue = that._currentValue = that._translator.adjust(that._options.currentValue); that.enabled = that._isEnabled(); if (that.enabled) { that._setupAnimation(); that._rootElement.attr({ fill: extractColor(that._options.color) }).linkAppend(); that._tracker.attach(that._trackerElement, that, that._trackerInfo) } return that }, resize: function(layout) { const that = this; that._rootElement.clear(); that._clear(); that.visible = that._isVisible(layout); if (that.visible) { extend(that._options, layout); that._actualPosition = that._translator.translate(that._actualValue); that._render(); that._trackerElement.attr(that._getTrackerSettings()); that._move() } return that }, value: function(arg, _noAnimation) { const that = this; let val; const rootElement = this._rootElement; let visibility = null; if (void 0 === arg) { return that._currentValue } if (null === arg) { visibility = "hidden"; that._currentValue = arg } else { val = that._translator.adjust(arg); if (that._currentValue !== val && _isFinite(val)) { that._currentValue = val; if (that.visible) { if (that._animation && !_noAnimation) { that._runAnimation(val) } else { that._actualValue = val; that._actualPosition = that._translator.translate(val); that._move() } } } } rootElement.attr({ visibility: visibility }); return that }, _isEnabled: null, _isVisible: null, _render: null, _clear: null, _move: null }); const COEFFICIENTS_MAP = {}; COEFFICIENTS_MAP["right-bottom"] = COEFFICIENTS_MAP.rb = [0, -1, -1, 0, 0, 1, 1, 0]; COEFFICIENTS_MAP["bottom-right"] = COEFFICIENTS_MAP.br = [-1, 0, 0, -1, 1, 0, 0, 1]; COEFFICIENTS_MAP["left-bottom"] = COEFFICIENTS_MAP.lb = [0, -1, 1, 0, 0, 1, -1, 0]; COEFFICIENTS_MAP["bottom-left"] = COEFFICIENTS_MAP.bl = [1, 0, 0, -1, -1, 0, 0, 1]; COEFFICIENTS_MAP["left-top"] = COEFFICIENTS_MAP.lt = [0, 1, 1, 0, 0, -1, -1, 0]; COEFFICIENTS_MAP["top-left"] = COEFFICIENTS_MAP.tl = [1, 0, 0, 1, -1, 0, 0, -1]; COEFFICIENTS_MAP["right-top"] = COEFFICIENTS_MAP.rt = [0, 1, -1, 0, 0, -1, 1, 0]; COEFFICIENTS_MAP["top-right"] = COEFFICIENTS_MAP.tr = [-1, 0, 0, 1, 1, 0, 0, -1]; function getTextCloudInfo(options) { let x = options.x; let y = options.y; const type = COEFFICIENTS_MAP[options.type]; const cloudWidth = options.cloudWidth; const cloudHeight = options.cloudHeight; let tailWidth; let tailHeight; const cx = x; const cy = y; tailWidth = tailHeight = options.tailLength; if (1 & type[0]) { tailHeight = Math.min(tailHeight, cloudHeight / 3) } else { tailWidth = Math.min(tailWidth, cloudWidth / 3) } return { cx: _round(cx + type[0] * tailWidth + (type[0] + type[2]) * cloudWidth / 2), cy: _round(cy + type[1] * tailHeight + (type[1] + type[3]) * cloudHeight / 2), points: [_round(x), _round(y), _round(x += type[0] * (cloudWidth + tailWidth)), _round(y += type[1] * (cloudHeight + tailHeight)), _round(x += type[2] * cloudWidth), _round(y += type[3] * cloudHeight), _round(x += type[4] * cloudWidth), _round(y += type[5] * cloudHeight), _round(x += type[6] * (cloudWidth - tailWidth)), _round(y += type[7] * (cloudHeight - tailHeight))] } } export const BaseTextCloudMarker = BaseIndicator.inherit({ _move: function() { const options = this._options; const textCloudOptions = this._getTextCloudOptions(); const text = _formatValue(this._actualValue, options.text); this._text.attr({ text: text }); const bBox = this._text.getBBox(); const x = textCloudOptions.x; const y = textCloudOptions.y; const cloudWidth = (bBox.width || text.length * this._textUnitWidth) + 2 * options.horizontalOffset; const cloudHeight = (bBox.height || this._textHeight) + 2 * options.verticalOffset; const info = getTextCloudInfo({ x: x, y: y, cloudWidth: cloudWidth, cloudHeight: cloudHeight, tailLength: options.arrowLength, type: this._correctCloudType(textCloudOptions.type, { x: x, y: y }, { width: cloudWidth, height: cloudHeight }) }); this._text.attr({ x: info.cx, y: info.cy + this._textVerticalOffset }); this._cloud.attr({ points: info.points }); this._trackerElement && this._trackerElement.attr({ points: info.points }) }, _measureText: function() { const that = this; let root; let text; let bBox; let sampleText; if (!that._textVerticalOffset) { root = that._createRoot().append(that._owner); sampleText = _getSampleText(that._translator, that._options.text); text = that._renderer.text(sampleText, 0, 0).attr({ align: "center" }).css(_patchFontOptions(that._options.text.font)).append(root); bBox = text.getBBox(); root.remove(); that._textVerticalOffset = -bBox.y - bBox.height / 2; that._textWidth = bBox.width; that._textHeight = bBox.height; that._textUnitWidth = that._textWidth / sampleText.length; that._textFullWidth = that._textWidth + 2 * that._options.horizontalOffset; that._textFullHeight = that._textHeight + 2 * that._options.verticalOffset } }, _render: function() { this._measureText(); this._cloud = this._cloud || this._renderer.path([], "area").append(this._rootElement); this._text = this._text || this._renderer.text().append(this._rootElement); this._text.attr({ align: "center" }).css(_patchFontOptions(this._options.text.font)) }, _clear: function() { delete this._cloud; delete this._text }, getTooltipParameters: function() { const position = this._getTextCloudOptions(); return { x: position.x, y: position.y, value: this._currentValue, color: this._options.color } }, _correctCloudType: type => type }); export const BaseRangeBar = BaseIndicator.inherit({ _measureText: function() { const that = this; let root; let text; let bBox; that._hasText = that._isTextVisible(); if (that._hasText && !that._textVerticalOffset) { root = that._createRoot().append(that._owner); text = that._renderer.text(_getSampleText(that._translator, that._options.text), 0, 0).attr({ class: "dxg-text", align: "center" }).css(_patchFontOptions(that._options.text.font)).append(root); bBox = text.getBBox(); root.remove(); that._textVerticalOffset = -bBox.y - bBox.height / 2; that._textWidth = bBox.width; that._textHeight = bBox.height } }, _move: function() { const that = this; that._updateBarItemsPositions(); if (that._hasText) { that._text.attr({ text: _formatValue(that._actualValue, that._options.text) }); that._updateTextPosition(); that._updateLinePosition() } }, _updateBarItems: function() { const that = this; const options = that._options; let spaceColor; const translator = that._translator; that._setBarSides(); that._startPosition = translator.translate(translator.getDomainStart()); that._endPosition = translator.translate(translator.getDomainEnd()); that._basePosition = translator.translate(options.baseValue); that._space = that._getSpace(); const backgroundColor = options.backgroundColor || "none"; if ("none" !== backgroundColor && that._space > 0) { spaceColor = options.containerBackgroundColor || "none" } else { that._space = 0; spaceColor = "none" } that._backItem1.attr({ fill: backgroundColor }); that._backItem2.attr({ fill: backgroundColor }); that._spaceItem1.attr({ fill: spaceColor }); that._spaceItem2.attr({ fill: spaceColor }) }, _getSpace: function() { return 0 }, _updateTextItems: function() { const that = this; if (that._hasText) { that._line = that._line || that._renderer.path([], "line").attr({ class: "dxg-main-bar", "stroke-linecap": "square" }).append(that._rootElement); that._text = that._text || that._renderer.text("", 0, 0).attr({ class: "dxg-text" }).append(that._rootElement); that._text.attr({ align: that._getTextAlign() }).css(that._getFontOptions()); that._setTextItemsSides() } else { if (that._line) { that._line.remove(); delete that._line } if (that._text) { that._text.remove(); delete that._text } } }, _isTextVisible: function() { return false }, _getTextAlign: function() { return "center" }, _getFontOptions: function() { const options = this._options; let font = options.text.font; if (!font || !font.color) { font = extend({}, font, { color: options.color }) } return _patchFontOptions(font) }, _updateBarItemsPositions: function() { const positions = this._getPositions(); this._backItem1.attr(this._buildItemSettings(positions.start, positions.back1)); this._backItem2.attr(this._buildItemSettings(positions.back2, positions.end)); this._spaceItem1.attr(this._buildItemSettings(positions.back1, positions.main1)); this._spaceItem2.attr(this._buildItemSettings(positions.main2, positions.back2)); this._mainItem.attr(this._buildItemSettings(positions.main1, positions.main2)); this._trackerElement && this._trackerElement.attr(this._buildItemSettings(positions.main1, positions.main2)) }, _render: function() { const that = this; that._measureText(); if (!that._backItem1) { that._backItem1 = that._createBarItem(); that._backItem1.attr({ class: "dxg-back-bar" }) } if (!that._backItem2) { that._backItem2 = that._createBarItem(); that._backItem2.attr({ class: "dxg-back-bar" }) } if (!that._spaceItem1) { that._spaceItem1 = that._createBarItem(); that._spaceItem1.attr({ class: "dxg-space-bar" }) } if (!that._spaceItem2) { that._spaceItem2 = that._createBarItem(); that._spaceItem2.attr({ class: "dxg-space-bar" }) } if (!that._mainItem) { that._mainItem = that._createBarItem(); that._mainItem.attr({ class: "dxg-main-bar" }) } that._updateBarItems(); that._updateTextItems() }, _clear: function() { delete this._backItem1; delete this._backItem2; delete this._spaceItem1; delete this._spaceItem2; delete this._mainItem; delete this._hasText; delete this._line; delete this._text }, getTooltipParameters: function() { const position = this._getTooltipPosition(); return { x: position.x, y: position.y, value: this._currentValue, color: this._options.color, offset: 0 } } });