UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

435 lines (433 loc) • 16.2 kB
/** * DevExtreme (esm/viz/gauges/circular_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 { BaseIndicator, BaseTextCloudMarker, BaseRangeBar } from "./base_indicators"; import { getCosAndSin, convertAngleToRendererSpace, normalizeAngle } from "../core/utils"; const _Number = Number; const _getCosAndSin = getCosAndSin; const _convertAngleToRendererSpace = convertAngleToRendererSpace; function correctRadius(layout, size) { if (layout && layout.radius - size <= 0) { layout.radius = size + 1 } return layout } const SimpleIndicator = BaseIndicator.inherit({ _move: function() { const options = this._options; const angle = _convertAngleToRendererSpace(this._actualPosition); this._rootElement.rotate(angle, options.x, options.y); this._trackerElement && this._trackerElement.rotate(angle, options.x, options.y) }, _isEnabled: function() { return this._options.width > 0 }, _isVisible: function(layout) { return layout.radius - _Number(this._options.indentFromCenter) > 0 }, _getTrackerSettings: function() { const options = this._options; const radius = this._getRadius(); const indentFromCenter = this._getIndentFromCenter(); const x = options.x; const y = options.y - (radius + indentFromCenter) / 2; let width = options.width / 2; let length = (radius - indentFromCenter) / 2; width > 10 || (width = 10); length > 10 || (length = 10); return { points: [x - width, y - length, x - width, y + length, x + width, y + length, x + width, y - length] } }, _render: function() { this._renderPointer() }, _clearPointer: function() { delete this._element }, _clear: function() { this._clearPointer() }, _getIndentFromCenter: function(radius) { return Number(this._options.indentFromCenter) || 0 }, _getRadius: function() { return 0 }, measure: function(layout) { const result = { max: layout.radius }; if (this._options.indentFromCenter < 0) { result.inverseHorizontalOffset = result.inverseVerticalOffset = -_Number(this._options.indentFromCenter) } return result }, getTooltipParameters: function() { const options = this._options; const cosSin = _getCosAndSin(this._actualPosition); const r = (this._getRadius() + this._getIndentFromCenter()) / 2; return { x: options.x + cosSin.cos * r, y: options.y - cosSin.sin * r, value: this._currentValue, color: options.color, offset: options.width / 2 } } }); const NeedleIndicator = SimpleIndicator.inherit({ _isVisible: function(layout) { const indentFromCenter = this._adjustOffset(Number(this._options.indentFromCenter), layout.radius); const offset = this._adjustOffset(Number(this._options.offset), layout.radius); return layout.radius - indentFromCenter - offset > 0 }, getOffset: function() { return 0 }, _adjustOffset: function(value, radius) { const minRadius = Number(this._options.beginAdaptingAtRadius); const diff = radius / minRadius; if (diff < 1) { value = Math.floor(value * diff) } return value || 0 }, _getIndentFromCenter: function(radius) { return this._adjustOffset(Number(this._options.indentFromCenter), this._options.radius) }, _getRadius: function() { const options = this._options; return options.radius - this._adjustOffset(Number(options.offset), options.radius) }, _renderSpindle: function() { const that = this; const options = that._options; const radius = options.radius; const spindleSize = 2 * this._adjustOffset(_Number(options.spindleSize) / 2, radius); let gapSize = 2 * this._adjustOffset(_Number(options.spindleGapSize) / 2, radius) || 0; if (gapSize > 0) { gapSize = gapSize <= spindleSize ? gapSize : spindleSize } if (spindleSize > 0) { that._spindleOuter = that._spindleOuter || that._renderer.circle().append(that._rootElement); that._spindleInner = that._spindleInner || that._renderer.circle().append(that._rootElement); that._spindleOuter.attr({ class: "dxg-spindle-border", cx: options.x, cy: options.y, r: spindleSize / 2 }); that._spindleInner.attr({ class: "dxg-spindle-hole", cx: options.x, cy: options.y, r: gapSize / 2, fill: options.containerBackgroundColor }) } }, _render: function() { this.callBase(); this._renderSpindle() }, _clear: function() { this.callBase(); delete this._spindleOuter; delete this._spindleInner } }); const rectangleNeedle = NeedleIndicator.inherit({ _renderPointer: function() { const options = this._options; const y2 = options.y - this._getRadius(); const y1 = options.y - this._getIndentFromCenter(); const x1 = options.x - options.width / 2; const x2 = x1 + _Number(options.width); this._element = this._element || this._renderer.path([], "area").append(this._rootElement); this._element.attr({ points: [x1, y1, x1, y2, x2, y2, x2, y1] }) } }); const triangleNeedle = NeedleIndicator.inherit({ _renderPointer: function() { const options = this._options; const y2 = options.y - this._getRadius(); const y1 = options.y - this._getIndentFromCenter(); const x1 = options.x - options.width / 2; const x2 = options.x + options.width / 2; this._element = this._element || this._renderer.path([], "area").append(this._rootElement); this._element.attr({ points: [x1, y1, options.x, y2, x2, y1] }) } }); const twoColorNeedle = NeedleIndicator.inherit({ _renderPointer: function() { const options = this._options; const x1 = options.x - options.width / 2; const x2 = options.x + options.width / 2; const y4 = options.y - this._getRadius(); const y1 = options.y - this._getIndentFromCenter(); const fraction = _Number(options.secondFraction) || 0; let y2; let y3; if (fraction >= 1) { y2 = y3 = y1 } else if (fraction <= 0) { y2 = y3 = y4 } else { y3 = y4 + (y1 - y4) * fraction; y2 = y3 + _Number(options.space) } this._firstElement = this._firstElement || this._renderer.path([], "area").append(this._rootElement); this._spaceElement = this._spaceElement || this._renderer.path([], "area").append(this._rootElement); this._secondElement = this._secondElement || this._renderer.path([], "area").append(this._rootElement); this._firstElement.attr({ points: [x1, y1, x1, y2, x2, y2, x2, y1] }); this._spaceElement.attr({ points: [x1, y2, x1, y3, x2, y3, x2, y2], class: "dxg-hole", fill: options.containerBackgroundColor }); this._secondElement.attr({ points: [x1, y3, x1, y4, x2, y4, x2, y3], class: "dxg-part", fill: options.secondColor }) }, _clearPointer: function() { delete this._firstElement; delete this._secondElement; delete this._spaceElement } }); const triangleMarker = SimpleIndicator.inherit({ _isEnabled: function() { return this._options.length > 0 && this._options.width > 0 }, _isVisible: layout => true, resize(layout) { return this.callBase(correctRadius(layout, 0)) }, _render: function() { const options = this._options; const x = options.x; const y1 = options.y - options.radius; const dx = options.width / 2 || 0; const y2 = y1 - _Number(options.length); this._element = this._element || this._renderer.path([], "area").append(this._rootElement); const settings = { points: [x, y1, x - dx, y2, x + dx, y2], stroke: "none", "stroke-width": 0, "stroke-linecap": "square" }; if (options.space > 0) { settings["stroke-width"] = Math.min(options.space, options.width / 4) || 0; settings.stroke = settings["stroke-width"] > 0 ? options.containerBackgroundColor || "none" : "none" } this._element.attr(settings).sharp() }, _clear: function() { delete this._element }, _getTrackerSettings: function() { const options = this._options; const x = options.x; const y = options.y - options.radius - options.length / 2; let width = options.width / 2; let length = options.length / 2; width > 10 || (width = 10); length > 10 || (length = 10); return { points: [x - width, y - length, x - width, y + length, x + width, y + length, x + width, y - length] } }, measure: function(layout) { return { min: layout.radius, max: layout.radius + _Number(this._options.length) } }, getTooltipParameters: function() { const options = this._options; const cosSin = _getCosAndSin(this._actualPosition); const r = options.radius + options.length / 2; const parameters = this.callBase(); parameters.x = options.x + cosSin.cos * r; parameters.y = options.y - cosSin.sin * r; parameters.offset = options.length / 2; return parameters } }); const textCloud = BaseTextCloudMarker.inherit({ _isEnabled: function() { return true }, _isVisible: layout => true, resize(layout) { return this.callBase(correctRadius(layout, 0)) }, _getTextCloudOptions: function() { const cosSin = _getCosAndSin(this._actualPosition); const nAngle = normalizeAngle(this._actualPosition); return { x: this._options.x + cosSin.cos * this._options.radius, y: this._options.y - cosSin.sin * this._options.radius, type: nAngle > 270 ? "left-top" : nAngle > 180 ? "top-right" : nAngle > 90 ? "right-bottom" : "bottom-left" } }, measure: function(layout) { const arrowLength = _Number(this._options.arrowLength) || 0; this._measureText(); const verticalOffset = this._textFullHeight + arrowLength; const horizontalOffset = this._textFullWidth + arrowLength; return { min: layout.radius, max: layout.radius, horizontalOffset: horizontalOffset, verticalOffset: verticalOffset, inverseHorizontalOffset: horizontalOffset, inverseVerticalOffset: verticalOffset } } }); const rangeBar = BaseRangeBar.inherit({ _isEnabled: function() { return this._options.size > 0 }, _isVisible: layout => true, resize(layout) { return this.callBase(correctRadius(layout, _Number(this._options.size))) }, _createBarItem: function() { return this._renderer.arc().attr({ "stroke-linejoin": "round" }).append(this._rootElement) }, _createTracker: function() { return this._renderer.arc().attr({ "stroke-linejoin": "round" }) }, _setBarSides: function() { this._maxSide = this._options.radius; this._minSide = this._maxSide - _Number(this._options.size) }, _getSpace: function() { const options = this._options; return options.space > 0 ? 180 * options.space / options.radius / Math.PI : 0 }, _isTextVisible: function() { const options = this._options.text || {}; return options.indent > 0 }, _setTextItemsSides: function() { const options = this._options; const indent = _Number(options.text.indent); this._lineFrom = options.y - options.radius; this._lineTo = this._lineFrom - indent; this._textRadius = options.radius + indent }, _getPositions: function() { const basePosition = this._basePosition; const actualPosition = this._actualPosition; let mainPosition1; let mainPosition2; if (basePosition >= actualPosition) { mainPosition1 = basePosition; mainPosition2 = actualPosition } else { mainPosition1 = actualPosition; mainPosition2 = basePosition } return { start: this._startPosition, end: this._endPosition, main1: mainPosition1, main2: mainPosition2, back1: Math.min(mainPosition1 + this._space, this._startPosition), back2: Math.max(mainPosition2 - this._space, this._endPosition) } }, _buildItemSettings: function(from, to) { return { x: this._options.x, y: this._options.y, innerRadius: this._minSide, outerRadius: this._maxSide, startAngle: to, endAngle: from } }, _updateTextPosition: function() { const cosSin = _getCosAndSin(this._actualPosition); let x = this._options.x + this._textRadius * cosSin.cos; let y = this._options.y - this._textRadius * cosSin.sin; x += cosSin.cos * this._textWidth * .6; y -= cosSin.sin * this._textHeight * .6; this._text.attr({ x: x, y: y + this._textVerticalOffset }) }, _updateLinePosition: function() { const x = this._options.x; let x1; let x2; if (this._basePosition > this._actualPosition) { x1 = x - 2; x2 = x } else if (this._basePosition < this._actualPosition) { x1 = x; x2 = x + 2 } else { x1 = x - 1; x2 = x + 1 } this._line.attr({ points: [x1, this._lineFrom, x1, this._lineTo, x2, this._lineTo, x2, this._lineFrom] }).rotate(_convertAngleToRendererSpace(this._actualPosition), x, this._options.y).sharp() }, _getTooltipPosition: function() { const cosSin = _getCosAndSin((this._basePosition + this._actualPosition) / 2); const r = (this._minSide + this._maxSide) / 2; return { x: this._options.x + cosSin.cos * r, y: this._options.y - cosSin.sin * r } }, measure: function(layout) { const that = this; const result = { min: layout.radius - _Number(that._options.size), max: layout.radius }; that._measureText(); if (that._hasText) { result.max += _Number(that._options.text.indent); result.horizontalOffset = that._textWidth; result.verticalOffset = that._textHeight } return result } }); export { rectangleNeedle as _default, rectangleNeedle as rectangleneedle, triangleNeedle as triangleneedle, twoColorNeedle as twocolorneedle, triangleMarker as trianglemarker, textCloud as textcloud, rangeBar as rangebar };