Node-Red configuration
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

d3-brush.js 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. // https://d3js.org/d3-brush/ v3.0.0 Copyright 2010-2021 Mike Bostock
  2. (function (global, factory) {
  3. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-dispatch'), require('d3-drag'), require('d3-interpolate'), require('d3-selection'), require('d3-transition')) :
  4. typeof define === 'function' && define.amd ? define(['exports', 'd3-dispatch', 'd3-drag', 'd3-interpolate', 'd3-selection', 'd3-transition'], factory) :
  5. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3, global.d3, global.d3, global.d3));
  6. }(this, (function (exports, d3Dispatch, d3Drag, d3Interpolate, d3Selection, d3Transition) { 'use strict';
  7. var constant = x => () => x;
  8. function BrushEvent(type, {
  9. sourceEvent,
  10. target,
  11. selection,
  12. mode,
  13. dispatch
  14. }) {
  15. Object.defineProperties(this, {
  16. type: {value: type, enumerable: true, configurable: true},
  17. sourceEvent: {value: sourceEvent, enumerable: true, configurable: true},
  18. target: {value: target, enumerable: true, configurable: true},
  19. selection: {value: selection, enumerable: true, configurable: true},
  20. mode: {value: mode, enumerable: true, configurable: true},
  21. _: {value: dispatch}
  22. });
  23. }
  24. function nopropagation(event) {
  25. event.stopImmediatePropagation();
  26. }
  27. function noevent(event) {
  28. event.preventDefault();
  29. event.stopImmediatePropagation();
  30. }
  31. var MODE_DRAG = {name: "drag"},
  32. MODE_SPACE = {name: "space"},
  33. MODE_HANDLE = {name: "handle"},
  34. MODE_CENTER = {name: "center"};
  35. const {abs, max, min} = Math;
  36. function number1(e) {
  37. return [+e[0], +e[1]];
  38. }
  39. function number2(e) {
  40. return [number1(e[0]), number1(e[1])];
  41. }
  42. var X = {
  43. name: "x",
  44. handles: ["w", "e"].map(type),
  45. input: function(x, e) { return x == null ? null : [[+x[0], e[0][1]], [+x[1], e[1][1]]]; },
  46. output: function(xy) { return xy && [xy[0][0], xy[1][0]]; }
  47. };
  48. var Y = {
  49. name: "y",
  50. handles: ["n", "s"].map(type),
  51. input: function(y, e) { return y == null ? null : [[e[0][0], +y[0]], [e[1][0], +y[1]]]; },
  52. output: function(xy) { return xy && [xy[0][1], xy[1][1]]; }
  53. };
  54. var XY = {
  55. name: "xy",
  56. handles: ["n", "w", "e", "s", "nw", "ne", "sw", "se"].map(type),
  57. input: function(xy) { return xy == null ? null : number2(xy); },
  58. output: function(xy) { return xy; }
  59. };
  60. var cursors = {
  61. overlay: "crosshair",
  62. selection: "move",
  63. n: "ns-resize",
  64. e: "ew-resize",
  65. s: "ns-resize",
  66. w: "ew-resize",
  67. nw: "nwse-resize",
  68. ne: "nesw-resize",
  69. se: "nwse-resize",
  70. sw: "nesw-resize"
  71. };
  72. var flipX = {
  73. e: "w",
  74. w: "e",
  75. nw: "ne",
  76. ne: "nw",
  77. se: "sw",
  78. sw: "se"
  79. };
  80. var flipY = {
  81. n: "s",
  82. s: "n",
  83. nw: "sw",
  84. ne: "se",
  85. se: "ne",
  86. sw: "nw"
  87. };
  88. var signsX = {
  89. overlay: +1,
  90. selection: +1,
  91. n: null,
  92. e: +1,
  93. s: null,
  94. w: -1,
  95. nw: -1,
  96. ne: +1,
  97. se: +1,
  98. sw: -1
  99. };
  100. var signsY = {
  101. overlay: +1,
  102. selection: +1,
  103. n: -1,
  104. e: null,
  105. s: +1,
  106. w: null,
  107. nw: -1,
  108. ne: -1,
  109. se: +1,
  110. sw: +1
  111. };
  112. function type(t) {
  113. return {type: t};
  114. }
  115. // Ignore right-click, since that should open the context menu.
  116. function defaultFilter(event) {
  117. return !event.ctrlKey && !event.button;
  118. }
  119. function defaultExtent() {
  120. var svg = this.ownerSVGElement || this;
  121. if (svg.hasAttribute("viewBox")) {
  122. svg = svg.viewBox.baseVal;
  123. return [[svg.x, svg.y], [svg.x + svg.width, svg.y + svg.height]];
  124. }
  125. return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
  126. }
  127. function defaultTouchable() {
  128. return navigator.maxTouchPoints || ("ontouchstart" in this);
  129. }
  130. // Like d3.local, but with the name “__brush” rather than auto-generated.
  131. function local(node) {
  132. while (!node.__brush) if (!(node = node.parentNode)) return;
  133. return node.__brush;
  134. }
  135. function empty(extent) {
  136. return extent[0][0] === extent[1][0]
  137. || extent[0][1] === extent[1][1];
  138. }
  139. function brushSelection(node) {
  140. var state = node.__brush;
  141. return state ? state.dim.output(state.selection) : null;
  142. }
  143. function brushX() {
  144. return brush$1(X);
  145. }
  146. function brushY() {
  147. return brush$1(Y);
  148. }
  149. function brush() {
  150. return brush$1(XY);
  151. }
  152. function brush$1(dim) {
  153. var extent = defaultExtent,
  154. filter = defaultFilter,
  155. touchable = defaultTouchable,
  156. keys = true,
  157. listeners = d3Dispatch.dispatch("start", "brush", "end"),
  158. handleSize = 6,
  159. touchending;
  160. function brush(group) {
  161. var overlay = group
  162. .property("__brush", initialize)
  163. .selectAll(".overlay")
  164. .data([type("overlay")]);
  165. overlay.enter().append("rect")
  166. .attr("class", "overlay")
  167. .attr("pointer-events", "all")
  168. .attr("cursor", cursors.overlay)
  169. .merge(overlay)
  170. .each(function() {
  171. var extent = local(this).extent;
  172. d3Selection.select(this)
  173. .attr("x", extent[0][0])
  174. .attr("y", extent[0][1])
  175. .attr("width", extent[1][0] - extent[0][0])
  176. .attr("height", extent[1][1] - extent[0][1]);
  177. });
  178. group.selectAll(".selection")
  179. .data([type("selection")])
  180. .enter().append("rect")
  181. .attr("class", "selection")
  182. .attr("cursor", cursors.selection)
  183. .attr("fill", "#777")
  184. .attr("fill-opacity", 0.3)
  185. .attr("stroke", "#fff")
  186. .attr("shape-rendering", "crispEdges");
  187. var handle = group.selectAll(".handle")
  188. .data(dim.handles, function(d) { return d.type; });
  189. handle.exit().remove();
  190. handle.enter().append("rect")
  191. .attr("class", function(d) { return "handle handle--" + d.type; })
  192. .attr("cursor", function(d) { return cursors[d.type]; });
  193. group
  194. .each(redraw)
  195. .attr("fill", "none")
  196. .attr("pointer-events", "all")
  197. .on("mousedown.brush", started)
  198. .filter(touchable)
  199. .on("touchstart.brush", started)
  200. .on("touchmove.brush", touchmoved)
  201. .on("touchend.brush touchcancel.brush", touchended)
  202. .style("touch-action", "none")
  203. .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
  204. }
  205. brush.move = function(group, selection, event) {
  206. if (group.tween) {
  207. group
  208. .on("start.brush", function(event) { emitter(this, arguments).beforestart().start(event); })
  209. .on("interrupt.brush end.brush", function(event) { emitter(this, arguments).end(event); })
  210. .tween("brush", function() {
  211. var that = this,
  212. state = that.__brush,
  213. emit = emitter(that, arguments),
  214. selection0 = state.selection,
  215. selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent),
  216. i = d3Interpolate.interpolate(selection0, selection1);
  217. function tween(t) {
  218. state.selection = t === 1 && selection1 === null ? null : i(t);
  219. redraw.call(that);
  220. emit.brush();
  221. }
  222. return selection0 !== null && selection1 !== null ? tween : tween(1);
  223. });
  224. } else {
  225. group
  226. .each(function() {
  227. var that = this,
  228. args = arguments,
  229. state = that.__brush,
  230. selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent),
  231. emit = emitter(that, args).beforestart();
  232. d3Transition.interrupt(that);
  233. state.selection = selection1 === null ? null : selection1;
  234. redraw.call(that);
  235. emit.start(event).brush(event).end(event);
  236. });
  237. }
  238. };
  239. brush.clear = function(group, event) {
  240. brush.move(group, null, event);
  241. };
  242. function redraw() {
  243. var group = d3Selection.select(this),
  244. selection = local(this).selection;
  245. if (selection) {
  246. group.selectAll(".selection")
  247. .style("display", null)
  248. .attr("x", selection[0][0])
  249. .attr("y", selection[0][1])
  250. .attr("width", selection[1][0] - selection[0][0])
  251. .attr("height", selection[1][1] - selection[0][1]);
  252. group.selectAll(".handle")
  253. .style("display", null)
  254. .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; })
  255. .attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; })
  256. .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; })
  257. .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; });
  258. }
  259. else {
  260. group.selectAll(".selection,.handle")
  261. .style("display", "none")
  262. .attr("x", null)
  263. .attr("y", null)
  264. .attr("width", null)
  265. .attr("height", null);
  266. }
  267. }
  268. function emitter(that, args, clean) {
  269. var emit = that.__brush.emitter;
  270. return emit && (!clean || !emit.clean) ? emit : new Emitter(that, args, clean);
  271. }
  272. function Emitter(that, args, clean) {
  273. this.that = that;
  274. this.args = args;
  275. this.state = that.__brush;
  276. this.active = 0;
  277. this.clean = clean;
  278. }
  279. Emitter.prototype = {
  280. beforestart: function() {
  281. if (++this.active === 1) this.state.emitter = this, this.starting = true;
  282. return this;
  283. },
  284. start: function(event, mode) {
  285. if (this.starting) this.starting = false, this.emit("start", event, mode);
  286. else this.emit("brush", event);
  287. return this;
  288. },
  289. brush: function(event, mode) {
  290. this.emit("brush", event, mode);
  291. return this;
  292. },
  293. end: function(event, mode) {
  294. if (--this.active === 0) delete this.state.emitter, this.emit("end", event, mode);
  295. return this;
  296. },
  297. emit: function(type, event, mode) {
  298. var d = d3Selection.select(this.that).datum();
  299. listeners.call(
  300. type,
  301. this.that,
  302. new BrushEvent(type, {
  303. sourceEvent: event,
  304. target: brush,
  305. selection: dim.output(this.state.selection),
  306. mode,
  307. dispatch: listeners
  308. }),
  309. d
  310. );
  311. }
  312. };
  313. function started(event) {
  314. if (touchending && !event.touches) return;
  315. if (!filter.apply(this, arguments)) return;
  316. var that = this,
  317. type = event.target.__data__.type,
  318. mode = (keys && event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (keys && event.altKey ? MODE_CENTER : MODE_HANDLE),
  319. signX = dim === Y ? null : signsX[type],
  320. signY = dim === X ? null : signsY[type],
  321. state = local(that),
  322. extent = state.extent,
  323. selection = state.selection,
  324. W = extent[0][0], w0, w1,
  325. N = extent[0][1], n0, n1,
  326. E = extent[1][0], e0, e1,
  327. S = extent[1][1], s0, s1,
  328. dx = 0,
  329. dy = 0,
  330. moving,
  331. shifting = signX && signY && keys && event.shiftKey,
  332. lockX,
  333. lockY,
  334. points = Array.from(event.touches || [event], t => {
  335. const i = t.identifier;
  336. t = d3Selection.pointer(t, that);
  337. t.point0 = t.slice();
  338. t.identifier = i;
  339. return t;
  340. });
  341. d3Transition.interrupt(that);
  342. var emit = emitter(that, arguments, true).beforestart();
  343. if (type === "overlay") {
  344. if (selection) moving = true;
  345. const pts = [points[0], points[1] || points[0]];
  346. state.selection = selection = [[
  347. w0 = dim === Y ? W : min(pts[0][0], pts[1][0]),
  348. n0 = dim === X ? N : min(pts[0][1], pts[1][1])
  349. ], [
  350. e0 = dim === Y ? E : max(pts[0][0], pts[1][0]),
  351. s0 = dim === X ? S : max(pts[0][1], pts[1][1])
  352. ]];
  353. if (points.length > 1) move(event);
  354. } else {
  355. w0 = selection[0][0];
  356. n0 = selection[0][1];
  357. e0 = selection[1][0];
  358. s0 = selection[1][1];
  359. }
  360. w1 = w0;
  361. n1 = n0;
  362. e1 = e0;
  363. s1 = s0;
  364. var group = d3Selection.select(that)
  365. .attr("pointer-events", "none");
  366. var overlay = group.selectAll(".overlay")
  367. .attr("cursor", cursors[type]);
  368. if (event.touches) {
  369. emit.moved = moved;
  370. emit.ended = ended;
  371. } else {
  372. var view = d3Selection.select(event.view)
  373. .on("mousemove.brush", moved, true)
  374. .on("mouseup.brush", ended, true);
  375. if (keys) view
  376. .on("keydown.brush", keydowned, true)
  377. .on("keyup.brush", keyupped, true);
  378. d3Drag.dragDisable(event.view);
  379. }
  380. redraw.call(that);
  381. emit.start(event, mode.name);
  382. function moved(event) {
  383. for (const p of event.changedTouches || [event]) {
  384. for (const d of points)
  385. if (d.identifier === p.identifier) d.cur = d3Selection.pointer(p, that);
  386. }
  387. if (shifting && !lockX && !lockY && points.length === 1) {
  388. const point = points[0];
  389. if (abs(point.cur[0] - point[0]) > abs(point.cur[1] - point[1]))
  390. lockY = true;
  391. else
  392. lockX = true;
  393. }
  394. for (const point of points)
  395. if (point.cur) point[0] = point.cur[0], point[1] = point.cur[1];
  396. moving = true;
  397. noevent(event);
  398. move(event);
  399. }
  400. function move(event) {
  401. const point = points[0], point0 = point.point0;
  402. var t;
  403. dx = point[0] - point0[0];
  404. dy = point[1] - point0[1];
  405. switch (mode) {
  406. case MODE_SPACE:
  407. case MODE_DRAG: {
  408. if (signX) dx = max(W - w0, min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
  409. if (signY) dy = max(N - n0, min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
  410. break;
  411. }
  412. case MODE_HANDLE: {
  413. if (points[1]) {
  414. if (signX) w1 = max(W, min(E, points[0][0])), e1 = max(W, min(E, points[1][0])), signX = 1;
  415. if (signY) n1 = max(N, min(S, points[0][1])), s1 = max(N, min(S, points[1][1])), signY = 1;
  416. } else {
  417. if (signX < 0) dx = max(W - w0, min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
  418. else if (signX > 0) dx = max(W - e0, min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
  419. if (signY < 0) dy = max(N - n0, min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
  420. else if (signY > 0) dy = max(N - s0, min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
  421. }
  422. break;
  423. }
  424. case MODE_CENTER: {
  425. if (signX) w1 = max(W, min(E, w0 - dx * signX)), e1 = max(W, min(E, e0 + dx * signX));
  426. if (signY) n1 = max(N, min(S, n0 - dy * signY)), s1 = max(N, min(S, s0 + dy * signY));
  427. break;
  428. }
  429. }
  430. if (e1 < w1) {
  431. signX *= -1;
  432. t = w0, w0 = e0, e0 = t;
  433. t = w1, w1 = e1, e1 = t;
  434. if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]);
  435. }
  436. if (s1 < n1) {
  437. signY *= -1;
  438. t = n0, n0 = s0, s0 = t;
  439. t = n1, n1 = s1, s1 = t;
  440. if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]);
  441. }
  442. if (state.selection) selection = state.selection; // May be set by brush.move!
  443. if (lockX) w1 = selection[0][0], e1 = selection[1][0];
  444. if (lockY) n1 = selection[0][1], s1 = selection[1][1];
  445. if (selection[0][0] !== w1
  446. || selection[0][1] !== n1
  447. || selection[1][0] !== e1
  448. || selection[1][1] !== s1) {
  449. state.selection = [[w1, n1], [e1, s1]];
  450. redraw.call(that);
  451. emit.brush(event, mode.name);
  452. }
  453. }
  454. function ended(event) {
  455. nopropagation(event);
  456. if (event.touches) {
  457. if (event.touches.length) return;
  458. if (touchending) clearTimeout(touchending);
  459. touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
  460. } else {
  461. d3Drag.dragEnable(event.view, moving);
  462. view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
  463. }
  464. group.attr("pointer-events", "all");
  465. overlay.attr("cursor", cursors.overlay);
  466. if (state.selection) selection = state.selection; // May be set by brush.move (on start)!
  467. if (empty(selection)) state.selection = null, redraw.call(that);
  468. emit.end(event, mode.name);
  469. }
  470. function keydowned(event) {
  471. switch (event.keyCode) {
  472. case 16: { // SHIFT
  473. shifting = signX && signY;
  474. break;
  475. }
  476. case 18: { // ALT
  477. if (mode === MODE_HANDLE) {
  478. if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
  479. if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
  480. mode = MODE_CENTER;
  481. move(event);
  482. }
  483. break;
  484. }
  485. case 32: { // SPACE; takes priority over ALT
  486. if (mode === MODE_HANDLE || mode === MODE_CENTER) {
  487. if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx;
  488. if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
  489. mode = MODE_SPACE;
  490. overlay.attr("cursor", cursors.selection);
  491. move(event);
  492. }
  493. break;
  494. }
  495. default: return;
  496. }
  497. noevent(event);
  498. }
  499. function keyupped(event) {
  500. switch (event.keyCode) {
  501. case 16: { // SHIFT
  502. if (shifting) {
  503. lockX = lockY = shifting = false;
  504. move(event);
  505. }
  506. break;
  507. }
  508. case 18: { // ALT
  509. if (mode === MODE_CENTER) {
  510. if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
  511. if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
  512. mode = MODE_HANDLE;
  513. move(event);
  514. }
  515. break;
  516. }
  517. case 32: { // SPACE
  518. if (mode === MODE_SPACE) {
  519. if (event.altKey) {
  520. if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
  521. if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
  522. mode = MODE_CENTER;
  523. } else {
  524. if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
  525. if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
  526. mode = MODE_HANDLE;
  527. }
  528. overlay.attr("cursor", cursors[type]);
  529. move(event);
  530. }
  531. break;
  532. }
  533. default: return;
  534. }
  535. noevent(event);
  536. }
  537. }
  538. function touchmoved(event) {
  539. emitter(this, arguments).moved(event);
  540. }
  541. function touchended(event) {
  542. emitter(this, arguments).ended(event);
  543. }
  544. function initialize() {
  545. var state = this.__brush || {selection: null};
  546. state.extent = number2(extent.apply(this, arguments));
  547. state.dim = dim;
  548. return state;
  549. }
  550. brush.extent = function(_) {
  551. return arguments.length ? (extent = typeof _ === "function" ? _ : constant(number2(_)), brush) : extent;
  552. };
  553. brush.filter = function(_) {
  554. return arguments.length ? (filter = typeof _ === "function" ? _ : constant(!!_), brush) : filter;
  555. };
  556. brush.touchable = function(_) {
  557. return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), brush) : touchable;
  558. };
  559. brush.handleSize = function(_) {
  560. return arguments.length ? (handleSize = +_, brush) : handleSize;
  561. };
  562. brush.keyModifiers = function(_) {
  563. return arguments.length ? (keys = !!_, brush) : keys;
  564. };
  565. brush.on = function() {
  566. var value = listeners.on.apply(listeners, arguments);
  567. return value === listeners ? brush : value;
  568. };
  569. return brush;
  570. }
  571. exports.brush = brush;
  572. exports.brushSelection = brushSelection;
  573. exports.brushX = brushX;
  574. exports.brushY = brushY;
  575. Object.defineProperty(exports, '__esModule', { value: true });
  576. })));