control_bar.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /**
  2. * DevExtreme (viz/vector_map/control_bar.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 _math = Math;
  11. var _min = _math.min;
  12. var _max = _math.max;
  13. var _round = _math.round;
  14. var _floor = _math.floor;
  15. var _sqrt = _math.sqrt;
  16. var vizUtils = require("../core/utils");
  17. var _parseScalar = vizUtils.parseScalar;
  18. var parseHorizontalAlignment = vizUtils.enumParser(["left", "center", "right"]);
  19. var parseVerticalAlignment = vizUtils.enumParser(["top", "bottom"]);
  20. var COMMAND_RESET = "command-reset";
  21. var COMMAND_MOVE_UP = "command-move-up";
  22. var COMMAND_MOVE_RIGHT = "command-move-right";
  23. var COMMAND_MOVE_DOWN = "command-move-down";
  24. var COMMAND_MOVE_LEFT = "command-move-left";
  25. var COMMAND_ZOOM_IN = "command-zoom-in";
  26. var COMMAND_ZOOM_OUT = "command-zoom-out";
  27. var COMMAND_ZOOM_DRAG_LINE = "command-zoom-drag-line";
  28. var COMMAND_ZOOM_DRAG = "command-zoom-drag";
  29. var EVENT_TARGET_TYPE = "control-bar";
  30. var FLAG_CENTERING = 1;
  31. var FLAG_ZOOMING = 2;
  32. var SIZE_OPTIONS = {
  33. bigCircleSize: 58,
  34. smallCircleSize: 28,
  35. buttonSize: 10,
  36. arrowButtonOffset: 20,
  37. incDecButtonSize: 11,
  38. incButtonOffset: 66,
  39. decButtonOffset: 227,
  40. sliderLineStartOffset: 88.5,
  41. sliderLineEndOffset: 205.5,
  42. sliderLength: 20,
  43. sliderWidth: 8,
  44. trackerGap: 4
  45. };
  46. var OFFSET_X = 30.5;
  47. var OFFSET_Y = 30.5;
  48. var TOTAL_WIDTH = 61;
  49. var TOTAL_HEIGHT = 274;
  50. var COMMAND_TO_TYPE_MAP = {};
  51. COMMAND_TO_TYPE_MAP[COMMAND_RESET] = ResetCommand;
  52. COMMAND_TO_TYPE_MAP[COMMAND_MOVE_UP] = COMMAND_TO_TYPE_MAP[COMMAND_MOVE_RIGHT] = COMMAND_TO_TYPE_MAP[COMMAND_MOVE_DOWN] = COMMAND_TO_TYPE_MAP[COMMAND_MOVE_LEFT] = MoveCommand;
  53. COMMAND_TO_TYPE_MAP[COMMAND_ZOOM_IN] = COMMAND_TO_TYPE_MAP[COMMAND_ZOOM_OUT] = ZoomCommand;
  54. COMMAND_TO_TYPE_MAP[COMMAND_ZOOM_DRAG] = ZoomDragCommand;
  55. function ControlBar(parameters) {
  56. var that = this;
  57. that._params = parameters;
  58. that._createElements(parameters.renderer, parameters.container, parameters.dataKey);
  59. parameters.layoutControl.addItem(that);
  60. that._subscribeToProjection(parameters.projection);
  61. that._subscribeToTracker(parameters.tracker);
  62. that._createCallbacks(parameters.projection)
  63. }
  64. ControlBar.prototype = {
  65. constructor: ControlBar,
  66. _flags: 0,
  67. dispose: function() {
  68. var that = this;
  69. that._params.layoutControl.removeItem(that);
  70. that._root.linkRemove().linkOff();
  71. that._offProjection();
  72. that._offTracker();
  73. that._params = that._root = that._offProjection = that._offTracker = that._callbacks = null
  74. },
  75. _subscribeToProjection: function(projection) {
  76. var that = this;
  77. that._offProjection = projection.on({
  78. engine: function() {
  79. that._update()
  80. },
  81. zoom: updateZoom,
  82. "max-zoom": function() {
  83. that._zoomPartition = projection.getZoomScalePartition();
  84. that._sliderUnitLength = that._sliderLineLength / that._zoomPartition;
  85. updateZoom()
  86. }
  87. });
  88. function updateZoom() {
  89. that._adjustZoom(projection.getScaledZoom())
  90. }
  91. },
  92. _subscribeToTracker: function(tracker) {
  93. var that = this;
  94. var isActive = false;
  95. that._offTracker = tracker.on({
  96. start: function(arg) {
  97. isActive = arg.data.name === EVENT_TARGET_TYPE;
  98. if (isActive) {
  99. that._processStart(arg.data.index, arg)
  100. }
  101. },
  102. move: function(arg) {
  103. if (isActive) {
  104. that._processMove(arg.data.index, arg)
  105. }
  106. },
  107. end: function() {
  108. if (isActive) {
  109. that._processEnd();
  110. isActive = false
  111. }
  112. }
  113. })
  114. },
  115. _createCallbacks: function(projection) {
  116. var that = this;
  117. that._callbacks = {
  118. reset: function(isCenter, isZoom) {
  119. if (isCenter) {
  120. projection.setCenter(null)
  121. }
  122. if (isZoom) {
  123. projection.setZoom(null)
  124. }
  125. },
  126. beginMove: function() {
  127. projection.beginMoveCenter()
  128. },
  129. endMove: function() {
  130. projection.endMoveCenter()
  131. },
  132. move: function(shift) {
  133. projection.moveCenter(shift)
  134. },
  135. zoom: function(_zoom) {
  136. projection.setScaledZoom(_zoom)
  137. }
  138. }
  139. },
  140. _createElements: function(renderer, container, dataKey) {
  141. var that = this;
  142. that._root = renderer.g().attr({
  143. "class": "dxm-control-bar"
  144. }).linkOn(container, "control-bar");
  145. var buttonsGroups = that._buttonsGroup = renderer.g().attr({
  146. "class": "dxm-control-buttons"
  147. }).append(that._root);
  148. var trackersGroup = renderer.g().attr({
  149. stroke: "none",
  150. "stroke-width": 0,
  151. fill: "#000000",
  152. opacity: 1e-4
  153. }).css({
  154. cursor: "pointer"
  155. }).append(that._root);
  156. that._createButtons(renderer, dataKey, buttonsGroups);
  157. that._createTrackers(renderer, dataKey, trackersGroup)
  158. },
  159. _createButtons: function(renderer, dataKey, group) {
  160. var that = this;
  161. var options = SIZE_OPTIONS;
  162. var size = options.buttonSize / 2;
  163. var offset1 = options.arrowButtonOffset - size;
  164. var offset2 = options.arrowButtonOffset;
  165. var incDecButtonSize = options.incDecButtonSize / 2;
  166. var directionOptions = {
  167. "stroke-linecap": "square",
  168. fill: "none"
  169. };
  170. var line = "line";
  171. renderer.circle(0, 0, options.bigCircleSize / 2).append(group);
  172. renderer.circle(0, 0, size).attr({
  173. fill: "none"
  174. }).append(group);
  175. renderer.path([-size, -offset1, 0, -offset2, size, -offset1], line).attr(directionOptions).append(group);
  176. renderer.path([offset1, -size, offset2, 0, offset1, size], line).attr(directionOptions).append(group);
  177. renderer.path([size, offset1, 0, offset2, -size, offset1], line).attr(directionOptions).append(group);
  178. renderer.path([-offset1, size, -offset2, 0, -offset1, -size], line).attr(directionOptions).append(group);
  179. renderer.circle(0, options.incButtonOffset, options.smallCircleSize / 2).append(group);
  180. renderer.path([
  181. [-incDecButtonSize, options.incButtonOffset, incDecButtonSize, options.incButtonOffset],
  182. [0, options.incButtonOffset - incDecButtonSize, 0, options.incButtonOffset + incDecButtonSize]
  183. ], "area").append(group);
  184. renderer.circle(0, options.decButtonOffset, options.smallCircleSize / 2).append(group);
  185. renderer.path([-incDecButtonSize, options.decButtonOffset, incDecButtonSize, options.decButtonOffset], "area").append(group);
  186. that._zoomLine = renderer.path([], "line").append(group);
  187. that._zoomDrag = renderer.rect(_floor(-options.sliderLength / 2), _floor(options.sliderLineEndOffset - options.sliderWidth / 2), options.sliderLength, options.sliderWidth).append(group);
  188. that._sliderLineLength = options.sliderLineEndOffset - options.sliderLineStartOffset
  189. },
  190. _createTrackers: function(renderer, dataKey, group) {
  191. var options = SIZE_OPTIONS;
  192. var size = _round((options.arrowButtonOffset - options.trackerGap) / 2);
  193. var offset1 = options.arrowButtonOffset - size;
  194. var offset2 = _round(_sqrt(options.bigCircleSize * options.bigCircleSize / 4 - size * size));
  195. var size2 = offset2 - offset1;
  196. renderer.rect(-size, -size, 2 * size, 2 * size).data(dataKey, {
  197. index: COMMAND_RESET,
  198. name: EVENT_TARGET_TYPE
  199. }).append(group);
  200. renderer.rect(-size, -offset2, 2 * size, size2).data(dataKey, {
  201. index: COMMAND_MOVE_UP,
  202. name: EVENT_TARGET_TYPE
  203. }).append(group);
  204. renderer.rect(offset1, -size, size2, 2 * size).data(dataKey, {
  205. index: COMMAND_MOVE_RIGHT,
  206. name: EVENT_TARGET_TYPE
  207. }).append(group);
  208. renderer.rect(-size, offset1, 2 * size, size2).data(dataKey, {
  209. index: COMMAND_MOVE_DOWN,
  210. name: EVENT_TARGET_TYPE
  211. }).append(group);
  212. renderer.rect(-offset2, -size, size2, 2 * size).data(dataKey, {
  213. index: COMMAND_MOVE_LEFT,
  214. name: EVENT_TARGET_TYPE
  215. }).append(group);
  216. renderer.circle(0, options.incButtonOffset, options.smallCircleSize / 2).data(dataKey, {
  217. index: COMMAND_ZOOM_IN,
  218. name: EVENT_TARGET_TYPE
  219. }).append(group);
  220. renderer.circle(0, options.decButtonOffset, options.smallCircleSize / 2).data(dataKey, {
  221. index: COMMAND_ZOOM_OUT,
  222. name: EVENT_TARGET_TYPE
  223. }).append(group);
  224. renderer.rect(-2, options.sliderLineStartOffset - 2, 4, options.sliderLineEndOffset - options.sliderLineStartOffset + 4).css({
  225. cursor: "default"
  226. }).data(dataKey, {
  227. index: COMMAND_ZOOM_DRAG_LINE,
  228. name: EVENT_TARGET_TYPE
  229. }).append(group);
  230. this._zoomDragTracker = renderer.rect(-options.sliderLength / 2, options.sliderLineEndOffset - options.sliderWidth / 2, options.sliderLength, options.sliderWidth).data(dataKey, {
  231. index: COMMAND_ZOOM_DRAG,
  232. name: EVENT_TARGET_TYPE
  233. }).append(group)
  234. },
  235. resize: function(size) {
  236. if (this._isActive) {
  237. this._root.attr({
  238. visibility: null !== size ? null : "hidden"
  239. })
  240. }
  241. },
  242. getLayoutOptions: function() {
  243. return this._isActive ? this._layoutOptions : null
  244. },
  245. locate: function(x, y) {
  246. this._root.attr({
  247. translateX: x + this._margin + OFFSET_X,
  248. translateY: y + this._margin + OFFSET_Y
  249. })
  250. },
  251. _update: function() {
  252. var that = this;
  253. that._isActive = that._isEnabled && that._flags && that._params.projection.isInvertible();
  254. if (that._isActive) {
  255. that._root.linkAppend()
  256. } else {
  257. that._root.linkRemove()
  258. }
  259. that._processEnd();
  260. that.updateLayout()
  261. },
  262. setInteraction: function(interaction) {
  263. var that = this;
  264. if (_parseScalar(interaction.centeringEnabled, true)) {
  265. that._flags |= FLAG_CENTERING
  266. } else {
  267. that._flags &= ~FLAG_CENTERING
  268. }
  269. if (_parseScalar(interaction.zoomingEnabled, true)) {
  270. that._flags |= FLAG_ZOOMING
  271. } else {
  272. that._flags &= ~FLAG_ZOOMING
  273. }
  274. that._update()
  275. },
  276. setOptions: function(options) {
  277. var that = this;
  278. that._isEnabled = !!_parseScalar(options.enabled, true);
  279. that._margin = options.margin || 0;
  280. that._layoutOptions = {
  281. width: 2 * that._margin + TOTAL_WIDTH,
  282. height: 2 * that._margin + TOTAL_HEIGHT,
  283. horizontalAlignment: parseHorizontalAlignment(options.horizontalAlignment, "left"),
  284. verticalAlignment: parseVerticalAlignment(options.verticalAlignment, "top")
  285. };
  286. that._buttonsGroup.attr({
  287. "stroke-width": options.borderWidth,
  288. stroke: options.borderColor,
  289. fill: options.color,
  290. "fill-opacity": options.opacity
  291. });
  292. that._update()
  293. },
  294. _adjustZoom: function(zoom) {
  295. var that = this;
  296. var start = SIZE_OPTIONS.sliderLineStartOffset;
  297. var end = SIZE_OPTIONS.sliderLineEndOffset;
  298. var h = SIZE_OPTIONS.sliderWidth;
  299. that._zoomFactor = _max(_min(_round(zoom), that._zoomPartition), 0);
  300. var transform = {
  301. translateY: -_round(that._zoomFactor * that._sliderUnitLength)
  302. };
  303. var y = end - h / 2 + transform.translateY;
  304. that._zoomLine.attr({
  305. points: [
  306. [0, start, 0, _max(start, y)],
  307. [0, _min(end, y + h), 0, end]
  308. ]
  309. });
  310. that._zoomDrag.attr(transform);
  311. that._zoomDragTracker.attr(transform)
  312. },
  313. _applyZoom: function() {
  314. this._callbacks.zoom(this._zoomFactor)
  315. },
  316. _processStart: function(command, arg) {
  317. var commandType;
  318. if (this._isActive) {
  319. commandType = COMMAND_TO_TYPE_MAP[command];
  320. this._command = commandType && commandType.flags & this._flags ? new commandType(this, command, arg) : null
  321. }
  322. },
  323. _processMove: function(command, arg) {
  324. this._command && this._command.update(command, arg)
  325. },
  326. _processEnd: function() {
  327. this._command && this._command.finish();
  328. this._command = null
  329. }
  330. };
  331. function disposeCommand(command) {
  332. delete command._owner;
  333. command.update = function() {};
  334. command.finish = function() {}
  335. }
  336. function ResetCommand(owner, command) {
  337. this._owner = owner;
  338. this._command = command
  339. }
  340. ResetCommand.flags = FLAG_CENTERING | FLAG_ZOOMING;
  341. ResetCommand.prototype.update = function(command) {
  342. command !== this._command && disposeCommand(this)
  343. };
  344. ResetCommand.prototype.finish = function() {
  345. var flags = this._owner._flags;
  346. this._owner._callbacks.reset(!!(flags & FLAG_CENTERING), !!(flags & FLAG_ZOOMING));
  347. disposeCommand(this)
  348. };
  349. function MoveCommand(owner, command, arg) {
  350. this._command = command;
  351. var timeout = null;
  352. var interval = 100;
  353. var dx = 0;
  354. var dy = 0;
  355. switch (this._command) {
  356. case COMMAND_MOVE_UP:
  357. dy = -10;
  358. break;
  359. case COMMAND_MOVE_RIGHT:
  360. dx = 10;
  361. break;
  362. case COMMAND_MOVE_DOWN:
  363. dy = 10;
  364. break;
  365. case COMMAND_MOVE_LEFT:
  366. dx = -10
  367. }
  368. function callback() {
  369. owner._callbacks.move([dx, dy]);
  370. timeout = setTimeout(callback, interval)
  371. }
  372. this._stop = function() {
  373. clearTimeout(timeout);
  374. owner._callbacks.endMove();
  375. this._stop = owner = null;
  376. return this
  377. };
  378. arg = null;
  379. owner._callbacks.beginMove();
  380. callback()
  381. }
  382. MoveCommand.flags = FLAG_CENTERING;
  383. MoveCommand.prototype.update = function(command) {
  384. this._command !== command && this.finish()
  385. };
  386. MoveCommand.prototype.finish = function() {
  387. disposeCommand(this._stop())
  388. };
  389. function ZoomCommand(owner, command) {
  390. this._owner = owner;
  391. this._command = command;
  392. var timeout = null;
  393. var interval = 150;
  394. var dZoom = this._command === COMMAND_ZOOM_IN ? 1 : -1;
  395. function callback() {
  396. owner._adjustZoom(owner._zoomFactor + dZoom);
  397. timeout = setTimeout(callback, interval)
  398. }
  399. this._stop = function() {
  400. clearTimeout(timeout);
  401. this._stop = owner = null;
  402. return this
  403. };
  404. callback()
  405. }
  406. ZoomCommand.flags = FLAG_ZOOMING;
  407. ZoomCommand.prototype.update = function(command) {
  408. this._command !== command && this.finish()
  409. };
  410. ZoomCommand.prototype.finish = function() {
  411. this._owner._applyZoom();
  412. disposeCommand(this._stop())
  413. };
  414. function ZoomDragCommand(owner, command, arg) {
  415. this._owner = owner;
  416. this._zoomFactor = owner._zoomFactor;
  417. this._pos = arg.y
  418. }
  419. ZoomDragCommand.flags = FLAG_ZOOMING;
  420. ZoomDragCommand.prototype.update = function(command, arg) {
  421. var owner = this._owner;
  422. owner._adjustZoom(this._zoomFactor + owner._zoomPartition * (this._pos - arg.y) / owner._sliderLineLength)
  423. };
  424. ZoomDragCommand.prototype.finish = function() {
  425. this._owner._applyZoom();
  426. disposeCommand(this)
  427. };
  428. exports.ControlBar = ControlBar;