circular_gauge.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /**
  2. * DevExtreme (viz/gauges/circular_gauge.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _isFinite = isFinite;
  11. var registerComponent = require("../../core/component_registrator");
  12. var objectUtils = require("../../core/utils/object");
  13. var extend = require("../../core/utils/extend").extend;
  14. var each = require("../../core/utils/iterator").each;
  15. var dxBaseGauge = require("./base_gauge").dxBaseGauge;
  16. var dxGauge = require("./common").dxGauge;
  17. var vizUtils = require("../core/utils");
  18. var _normalizeAngle = vizUtils.normalizeAngle;
  19. var _getCosAndSin = vizUtils.getCosAndSin;
  20. var circularIndicatorsModule = require("./circular_indicators");
  21. var createIndicatorCreator = require("./common").createIndicatorCreator;
  22. var CircularRangeContainer = require("./circular_range_container");
  23. var _abs = Math.abs;
  24. var _max = Math.max;
  25. var _min = Math.min;
  26. var _round = Math.round;
  27. var _each = each;
  28. var PI = Math.PI;
  29. function getSides(startAngle, endAngle) {
  30. var startCosSin = _getCosAndSin(startAngle);
  31. var endCosSin = _getCosAndSin(endAngle);
  32. var startCos = startCosSin.cos;
  33. var startSin = startCosSin.sin;
  34. var endCos = endCosSin.cos;
  35. var endSin = endCosSin.sin;
  36. return {
  37. left: startSin <= 0 && endSin >= 0 || startSin <= 0 && endSin <= 0 && startCos <= endCos || startSin >= 0 && endSin >= 0 && startCos >= endCos ? -1 : _min(startCos, endCos, 0),
  38. right: startSin >= 0 && endSin <= 0 || startSin >= 0 && endSin >= 0 && startCos >= endCos || startSin <= 0 && endSin <= 0 && startCos <= endCos ? 1 : _max(startCos, endCos, 0),
  39. up: startCos <= 0 && endCos >= 0 || startCos <= 0 && endCos <= 0 && startSin >= endSin || startCos >= 0 && endCos >= 0 && startSin <= endSin ? -1 : -_max(startSin, endSin, 0),
  40. down: startCos >= 0 && endCos <= 0 || startCos >= 0 && endCos >= 0 && startSin <= endSin || startCos <= 0 && endCos <= 0 && startSin >= endSin ? 1 : -_min(startSin, endSin, 0)
  41. }
  42. }
  43. var dxCircularGauge = dxGauge.inherit({
  44. _rootClass: "dxg-circular-gauge",
  45. _factoryMethods: {
  46. rangeContainer: "createCircularRangeContainer",
  47. indicator: "createCircularIndicator"
  48. },
  49. _gridSpacingFactor: 17,
  50. _scaleTypes: {
  51. type: "polarAxes",
  52. drawingType: "circular"
  53. },
  54. _getThemeManagerOptions: function() {
  55. var options = this.callBase.apply(this, arguments);
  56. options.subTheme = "_circular";
  57. return options
  58. },
  59. _updateScaleTickIndent: function(scaleOptions) {
  60. var indentFromTick = scaleOptions.label.indentFromTick;
  61. var length = scaleOptions.tick.visible ? scaleOptions.tick.length : 0;
  62. var textParams = this._scale.measureLabels(extend({}, this._canvas));
  63. var tickCorrection = length;
  64. if ("inside" === scaleOptions.orientation) {
  65. tickCorrection = 0
  66. } else {
  67. if ("center" === scaleOptions.orientation) {
  68. tickCorrection = .5 * length
  69. }
  70. }
  71. scaleOptions.label.indentFromAxis = indentFromTick >= 0 ? indentFromTick + tickCorrection : indentFromTick - tickCorrection - _max(textParams.width, textParams.height);
  72. this._scale.updateOptions(scaleOptions)
  73. },
  74. _setupCodomain: function() {
  75. var that = this;
  76. var geometry = that.option("geometry") || {};
  77. var startAngle = geometry.startAngle;
  78. var endAngle = geometry.endAngle;
  79. var sides;
  80. startAngle = _isFinite(startAngle) ? _normalizeAngle(startAngle) : 225;
  81. endAngle = _isFinite(endAngle) ? _normalizeAngle(endAngle) : -45;
  82. if (_abs(startAngle - endAngle) < 1) {
  83. endAngle -= 360;
  84. sides = {
  85. left: -1,
  86. up: -1,
  87. right: 1,
  88. down: 1
  89. }
  90. } else {
  91. startAngle < endAngle && (endAngle -= 360);
  92. sides = getSides(startAngle, endAngle)
  93. }
  94. that._area = {
  95. x: 0,
  96. y: 0,
  97. radius: 100,
  98. startCoord: startAngle,
  99. endCoord: endAngle,
  100. sides: sides
  101. };
  102. that._translator.setCodomain(startAngle, endAngle)
  103. },
  104. _shiftScale: function(layout) {
  105. var scale = this._scale;
  106. var canvas = scale.getCanvas();
  107. canvas.width = canvas.height = 2 * layout.radius;
  108. scale.draw(canvas);
  109. var centerCoords = scale.getCenter();
  110. scale.shift({
  111. right: layout.x - centerCoords.x,
  112. bottom: layout.y - centerCoords.y
  113. })
  114. },
  115. _getScaleLayoutValue: function() {
  116. return this._area.radius
  117. },
  118. _getTicksOrientation: function(scaleOptions) {
  119. return scaleOptions.orientation
  120. },
  121. _getTicksCoefficients: function(options) {
  122. var coefs = {
  123. inner: 0,
  124. outer: 1
  125. };
  126. if ("inside" === options.orientation) {
  127. coefs.inner = 1;
  128. coefs.outer = 0
  129. } else {
  130. if ("center" === options.orientation) {
  131. coefs.inner = coefs.outer = .5
  132. }
  133. }
  134. return coefs
  135. },
  136. _correctScaleIndents: function(result, indentFromTick, textParams) {
  137. if (indentFromTick >= 0) {
  138. result.horizontalOffset = indentFromTick + textParams.width;
  139. result.verticalOffset = indentFromTick + textParams.height
  140. } else {
  141. result.horizontalOffset = result.verticalOffset = 0;
  142. result.min -= -indentFromTick + _max(textParams.width, textParams.height)
  143. }
  144. result.inverseHorizontalOffset = textParams.width / 2;
  145. result.inverseVerticalOffset = textParams.height / 2
  146. },
  147. _measureMainElements: function(elements, scaleMeasurement) {
  148. var that = this;
  149. var radius = that._area.radius;
  150. var maxRadius = 0;
  151. var minRadius = 1 / 0;
  152. var maxHorizontalOffset = 0;
  153. var maxVerticalOffset = 0;
  154. var maxInverseHorizontalOffset = 0;
  155. var maxInverseVerticalOffset = 0;
  156. var scale = that._scale;
  157. _each(elements.concat(scale), function(_, element) {
  158. var bounds = element.measure ? element.measure({
  159. radius: radius - element.getOffset()
  160. }) : scaleMeasurement;
  161. bounds.min > 0 && (minRadius = _min(minRadius, bounds.min));
  162. bounds.max > 0 && (maxRadius = _max(maxRadius, bounds.max));
  163. bounds.horizontalOffset > 0 && (maxHorizontalOffset = _max(maxHorizontalOffset, bounds.max + bounds.horizontalOffset));
  164. bounds.verticalOffset > 0 && (maxVerticalOffset = _max(maxVerticalOffset, bounds.max + bounds.verticalOffset));
  165. bounds.inverseHorizontalOffset > 0 && (maxInverseHorizontalOffset = _max(maxInverseHorizontalOffset, bounds.inverseHorizontalOffset));
  166. bounds.inverseVerticalOffset > 0 && (maxInverseVerticalOffset = _max(maxInverseVerticalOffset, bounds.inverseVerticalOffset))
  167. });
  168. maxHorizontalOffset = _max(maxHorizontalOffset - maxRadius, 0);
  169. maxVerticalOffset = _max(maxVerticalOffset - maxRadius, 0);
  170. return {
  171. minRadius: minRadius,
  172. maxRadius: maxRadius,
  173. horizontalMargin: maxHorizontalOffset,
  174. verticalMargin: maxVerticalOffset,
  175. inverseHorizontalMargin: maxInverseHorizontalOffset,
  176. inverseVerticalMargin: maxInverseVerticalOffset
  177. }
  178. },
  179. _applyMainLayout: function(elements, scaleMeasurement) {
  180. var measurements = this._measureMainElements(elements, scaleMeasurement);
  181. var area = this._area;
  182. var sides = area.sides;
  183. var margins = {
  184. left: (sides.left < -.1 ? measurements.horizontalMargin : measurements.inverseHorizontalMargin) || 0,
  185. right: (sides.right > .1 ? measurements.horizontalMargin : measurements.inverseHorizontalMargin) || 0,
  186. top: (sides.up < -.1 ? measurements.verticalMargin : measurements.inverseVerticalMargin) || 0,
  187. bottom: (sides.down > .1 ? measurements.verticalMargin : measurements.inverseVerticalMargin) || 0
  188. };
  189. var rect = selectRectByAspectRatio(this._innerRect, (sides.down - sides.up) / (sides.right - sides.left), margins);
  190. var radius = _min(getWidth(rect) / (sides.right - sides.left), getHeight(rect) / (sides.down - sides.up));
  191. radius = radius - measurements.maxRadius + area.radius;
  192. var x = rect.left - getWidth(rect) * sides.left / (sides.right - sides.left);
  193. var y = rect.top - getHeight(rect) * sides.up / (sides.down - sides.up);
  194. area.x = _round(x);
  195. area.y = _round(y);
  196. area.radius = radius;
  197. rect.left -= margins.left;
  198. rect.right += margins.right;
  199. rect.top -= margins.top;
  200. rect.bottom += margins.bottom;
  201. this._innerRect = rect
  202. },
  203. _getElementLayout: function(offset) {
  204. return {
  205. x: this._area.x,
  206. y: this._area.y,
  207. radius: _round(this._area.radius - offset)
  208. }
  209. },
  210. _getApproximateScreenRange: function() {
  211. var that = this;
  212. var area = that._area;
  213. var r = _min(that._canvas.width / (area.sides.right - area.sides.left), that._canvas.height / (area.sides.down - area.sides.up));
  214. r > area.totalRadius && (r = area.totalRadius);
  215. r = .8 * r;
  216. return -that._translator.getCodomainRange() * r * PI / 180
  217. },
  218. _getDefaultSize: function() {
  219. return {
  220. width: 300,
  221. height: 300
  222. }
  223. },
  224. _factory: objectUtils.clone(dxBaseGauge.prototype._factory)
  225. });
  226. function getWidth(rect) {
  227. return rect.right - rect.left
  228. }
  229. function getHeight(rect) {
  230. return rect.bottom - rect.top
  231. }
  232. function selectRectByAspectRatio(srcRect, aspectRatio, margins) {
  233. var rect = extend({}, srcRect);
  234. var selfAspectRatio;
  235. var width = 0;
  236. var height = 0;
  237. margins = margins || {};
  238. if (aspectRatio > 0) {
  239. rect.left += margins.left || 0;
  240. rect.right -= margins.right || 0;
  241. rect.top += margins.top || 0;
  242. rect.bottom -= margins.bottom || 0;
  243. if (getWidth(rect) > 0 && getHeight(rect) > 0) {
  244. selfAspectRatio = getHeight(rect) / getWidth(rect);
  245. if (selfAspectRatio > 1) {
  246. aspectRatio < selfAspectRatio ? width = getWidth(rect) : height = getHeight(rect)
  247. } else {
  248. aspectRatio > selfAspectRatio ? height = getHeight(rect) : width = getWidth(rect)
  249. }
  250. width > 0 || (width = height / aspectRatio);
  251. height > 0 || (height = width * aspectRatio);
  252. width = (getWidth(rect) - width) / 2;
  253. height = (getHeight(rect) - height) / 2;
  254. rect.left += width;
  255. rect.right -= width;
  256. rect.top += height;
  257. rect.bottom -= height
  258. } else {
  259. rect.left = rect.right = (rect.left + rect.right) / 2;
  260. rect.top = rect.bottom = (rect.top + rect.bottom) / 2
  261. }
  262. }
  263. return rect
  264. }
  265. var indicators = dxCircularGauge.prototype._factory.indicators = {};
  266. dxCircularGauge.prototype._factory.createIndicator = createIndicatorCreator(indicators);
  267. indicators._default = circularIndicatorsModule._default;
  268. indicators.rectangleneedle = circularIndicatorsModule.rectangleneedle;
  269. indicators.triangleneedle = circularIndicatorsModule.triangleneedle;
  270. indicators.twocolorneedle = circularIndicatorsModule.twocolorneedle;
  271. indicators.trianglemarker = circularIndicatorsModule.trianglemarker;
  272. indicators.textcloud = circularIndicatorsModule.textcloud;
  273. indicators.rangebar = circularIndicatorsModule.rangebar;
  274. dxCircularGauge.prototype._factory.RangeContainer = CircularRangeContainer;
  275. registerComponent("dxCircularGauge", dxCircularGauge);
  276. module.exports = dxCircularGauge;