@jrkasprzyk/parcoord-es 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +160 -0
  3. package/dist/parcoords.css +61 -0
  4. package/dist/parcoords.esm.js +4132 -0
  5. package/dist/parcoords.esm.js.map +1 -0
  6. package/dist/parcoords.js +4130 -0
  7. package/dist/parcoords.js.map +1 -0
  8. package/dist/parcoords.standalone.js +11233 -0
  9. package/dist/parcoords.standalone.js.map +1 -0
  10. package/package.json +89 -0
  11. package/src/api/adjacentPairs.js +10 -0
  12. package/src/api/applyAxisConfig.js +35 -0
  13. package/src/api/applyDimensionDefaults.js +25 -0
  14. package/src/api/autoscale.js +133 -0
  15. package/src/api/axisDots.js +27 -0
  16. package/src/api/brushMode.js +50 -0
  17. package/src/api/brushReset.js +34 -0
  18. package/src/api/brushable.js +81 -0
  19. package/src/api/clear.js +21 -0
  20. package/src/api/commonScale.js +45 -0
  21. package/src/api/computeRealCentroids.js +8 -0
  22. package/src/api/createAxes.js +101 -0
  23. package/src/api/detectDimensionTypes.js +12 -0
  24. package/src/api/detectDimensions.js +7 -0
  25. package/src/api/flip.js +11 -0
  26. package/src/api/getOrderedDimensionKeys.js +8 -0
  27. package/src/api/highlight.js +26 -0
  28. package/src/api/init.js +53 -0
  29. package/src/api/interactive.js +7 -0
  30. package/src/api/intersection.js +16 -0
  31. package/src/api/mark.js +20 -0
  32. package/src/api/mergeParcoords.js +86 -0
  33. package/src/api/removeAxes.js +9 -0
  34. package/src/api/render.js +26 -0
  35. package/src/api/renderBrushed.js +39 -0
  36. package/src/api/renderDefault.js +27 -0
  37. package/src/api/renderMarked.js +34 -0
  38. package/src/api/reorder.js +37 -0
  39. package/src/api/reorderable.js +41 -0
  40. package/src/api/resize.js +36 -0
  41. package/src/api/scale.js +10 -0
  42. package/src/api/selected.js +209 -0
  43. package/src/api/shadows.js +9 -0
  44. package/src/api/sortDimensions.js +13 -0
  45. package/src/api/sortDimensionsByRowData.js +20 -0
  46. package/src/api/toString.js +11 -0
  47. package/src/api/toType.js +9 -0
  48. package/src/api/toTypeCoerceNumbers.js +7 -0
  49. package/src/api/unhighlight.js +12 -0
  50. package/src/api/unmark.js +12 -0
  51. package/src/api/updateAxes.js +103 -0
  52. package/src/bindEvents.js +60 -0
  53. package/src/brush/1d/brushExtents.js +73 -0
  54. package/src/brush/1d/brushFor.js +92 -0
  55. package/src/brush/1d/brushReset.js +36 -0
  56. package/src/brush/1d/index.js +20 -0
  57. package/src/brush/1d/install.js +41 -0
  58. package/src/brush/1d/selected.js +79 -0
  59. package/src/brush/1d/uninstall.js +12 -0
  60. package/src/brush/1d-multi/brushExtents.js +101 -0
  61. package/src/brush/1d-multi/brushFor.js +13 -0
  62. package/src/brush/1d-multi/brushReset.js +53 -0
  63. package/src/brush/1d-multi/drawBrushes.js +36 -0
  64. package/src/brush/1d-multi/index.js +20 -0
  65. package/src/brush/1d-multi/install.js +29 -0
  66. package/src/brush/1d-multi/newBrush.js +102 -0
  67. package/src/brush/1d-multi/selected.js +160 -0
  68. package/src/brush/1d-multi/uninstall.js +12 -0
  69. package/src/brush/angular/brushReset.js +14 -0
  70. package/src/brush/angular/index.js +19 -0
  71. package/src/brush/angular/install.js +141 -0
  72. package/src/brush/angular/onDrag.js +109 -0
  73. package/src/brush/angular/onDragEnd.js +30 -0
  74. package/src/brush/angular/onDragStart.js +38 -0
  75. package/src/brush/angular/removeStrum.js +12 -0
  76. package/src/brush/angular/selected.js +63 -0
  77. package/src/brush/angular/uninstall.js +17 -0
  78. package/src/brush/angular/util/hypothenuse.js +3 -0
  79. package/src/brush/consecutive.js +11 -0
  80. package/src/brush/dimensionsForPoint.js +32 -0
  81. package/src/brush/invertByScale.js +24 -0
  82. package/src/brush/strums/brushReset.js +14 -0
  83. package/src/brush/strums/index.js +19 -0
  84. package/src/brush/strums/install.js +81 -0
  85. package/src/brush/strums/onDrag.js +83 -0
  86. package/src/brush/strums/onDragEnd.js +20 -0
  87. package/src/brush/strums/onDragStart.js +33 -0
  88. package/src/brush/strums/removeStrum.js +10 -0
  89. package/src/brush/strums/selected.js +52 -0
  90. package/src/brush/strums/uninstall.js +16 -0
  91. package/src/index.js +226 -0
  92. package/src/parallel-coordinates.css +61 -0
  93. package/src/state/defaultConfig.js +36 -0
  94. package/src/state/index.js +86 -0
  95. package/src/state/sideEffects.js +89 -0
  96. package/src/util/colorPath.js +71 -0
  97. package/src/util/computeCentroids.js +44 -0
  98. package/src/util/computeClusterCentroids.js +33 -0
  99. package/src/util/computeControlPoints.js +38 -0
  100. package/src/util/dimensionLabels.js +11 -0
  101. package/src/util/flipAxisAndUpdatePCP.js +19 -0
  102. package/src/util/functor.js +3 -0
  103. package/src/util/getRange.js +24 -0
  104. package/src/util/getset.js +23 -0
  105. package/src/util/height.js +3 -0
  106. package/src/util/isBrushed.js +15 -0
  107. package/src/util/renderQueue.js +67 -0
  108. package/src/util/rotateLabels.js +18 -0
  109. package/src/util/width.js +3 -0
@@ -0,0 +1,20 @@
1
+ import brushExtents from './brushExtents';
2
+ import install from './install';
3
+ import selected from './selected';
4
+ import uninstall from './uninstall';
5
+
6
+ const install1DAxes = (brushGroup, config, pc, events) => {
7
+ const state = {
8
+ brushes: {},
9
+ brushNodes: {},
10
+ };
11
+
12
+ brushGroup.modes['1D-axes'] = {
13
+ install: install(state, config, pc, events, brushGroup),
14
+ uninstall: uninstall(state, pc),
15
+ selected: selected(state, config, brushGroup),
16
+ brushState: brushExtents(state, config, pc),
17
+ };
18
+ };
19
+
20
+ export default install1DAxes;
@@ -0,0 +1,41 @@
1
+ import { select } from 'd3-selection';
2
+ import brushExtents from './brushExtents';
3
+ import brushReset from './brushReset';
4
+ import brushFor from './brushFor';
5
+
6
+ const install = (state, config, pc, events, brushGroup) => () => {
7
+ if (!pc.g()) {
8
+ pc.createAxes();
9
+ }
10
+
11
+ // Add and store a brush for each axis.
12
+ const brush = pc
13
+ .g()
14
+ .append('svg:g')
15
+ .attr('class', 'brush')
16
+ .each(function(d) {
17
+ select(this).call(
18
+ brushFor(state, config, pc, events, brushGroup)(d, select(this))
19
+ );
20
+ });
21
+ brush
22
+ .selectAll('rect')
23
+ .style('visibility', null)
24
+ .attr('x', -15)
25
+ .attr('width', 30);
26
+
27
+ brush.selectAll('rect.background').style('fill', 'transparent');
28
+
29
+ brush
30
+ .selectAll('rect.extent')
31
+ .style('fill', 'rgba(255,255,255,0.25)')
32
+ .style('stroke', 'rgba(0,0,0,0.6)');
33
+
34
+ brush.selectAll('.resize rect').style('fill', 'rgba(0,0,0,0.1)');
35
+
36
+ pc.brushExtents = brushExtents(state, config, pc);
37
+ pc.brushReset = brushReset(state, config, pc);
38
+ return pc;
39
+ };
40
+
41
+ export default install;
@@ -0,0 +1,79 @@
1
+ import { brushSelection } from 'd3-brush';
2
+ //https://github.com/d3/d3-brush/issues/10
3
+
4
+ // data within extents
5
+ const selected = (state, config, brushGroup) => () => {
6
+ const { brushNodes } = state;
7
+ const is_brushed = p =>
8
+ brushNodes[p] && brushSelection(brushNodes[p]) !== null;
9
+
10
+ const actives = Object.keys(config.dimensions).filter(is_brushed);
11
+ const extents = actives.map(p => {
12
+ const _brushRange = brushSelection(brushNodes[p]);
13
+
14
+ if (typeof config.dimensions[p].yscale.invert === 'function') {
15
+ return [
16
+ config.dimensions[p].yscale.invert(_brushRange[1]),
17
+ config.dimensions[p].yscale.invert(_brushRange[0]),
18
+ ];
19
+ } else {
20
+ return _brushRange;
21
+ }
22
+ });
23
+ // We don't want to return the full data set when there are no axes brushed.
24
+ // Actually, when there are no axes brushed, by definition, no items are
25
+ // selected. So, let's avoid the filtering and just return false.
26
+ //if (actives.length === 0) return false;
27
+
28
+ // Resolves broken examples for now. They expect to get the full dataset back from empty brushes
29
+ if (actives.length === 0) return config.data;
30
+
31
+ // test if within range
32
+ const within = {
33
+ date: (d, p, dimension) => {
34
+ if (typeof config.dimensions[p].yscale.bandwidth === 'function') {
35
+ // if it is ordinal
36
+ return (
37
+ extents[dimension][0] <= config.dimensions[p].yscale(d[p]) &&
38
+ config.dimensions[p].yscale(d[p]) <= extents[dimension][1]
39
+ );
40
+ } else {
41
+ return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1];
42
+ }
43
+ },
44
+ number: (d, p, dimension) => {
45
+ if (typeof config.dimensions[p].yscale.bandwidth === 'function') {
46
+ // if it is ordinal
47
+ return (
48
+ extents[dimension][0] <= config.dimensions[p].yscale(d[p]) &&
49
+ config.dimensions[p].yscale(d[p]) <= extents[dimension][1]
50
+ );
51
+ } else {
52
+ return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1];
53
+ }
54
+ },
55
+ string: (d, p, dimension) => {
56
+ return (
57
+ extents[dimension][0] <= config.dimensions[p].yscale(d[p]) &&
58
+ config.dimensions[p].yscale(d[p]) <= extents[dimension][1]
59
+ );
60
+ },
61
+ };
62
+
63
+ return config.data.filter(d => {
64
+ switch (brushGroup.predicate) {
65
+ case 'AND':
66
+ return actives.every(function(p, dimension) {
67
+ return within[config.dimensions[p].type](d, p, dimension);
68
+ });
69
+ case 'OR':
70
+ return actives.some(function(p, dimension) {
71
+ return within[config.dimensions[p].type](d, p, dimension);
72
+ });
73
+ default:
74
+ throw new Error('Unknown brush predicate ' + config.brushPredicate);
75
+ }
76
+ });
77
+ };
78
+
79
+ export default selected;
@@ -0,0 +1,12 @@
1
+ const uninstall = (state, pc) => () => {
2
+ if (pc.g() !== undefined && pc.g() !== null)
3
+ pc.g()
4
+ .selectAll('.brush')
5
+ .remove();
6
+
7
+ state.brushes = {};
8
+ delete pc.brushExtents;
9
+ delete pc.brushReset;
10
+ };
11
+
12
+ export default uninstall;
@@ -0,0 +1,101 @@
1
+ import { select } from 'd3-selection';
2
+ import { brushSelection } from 'd3-brush';
3
+ import newBrush from './newBrush';
4
+ import drawBrushes from './drawBrushes';
5
+ import invertByScale from '../invertByScale';
6
+
7
+ /**
8
+ *
9
+ * extents are in format of [[2,6], [3,5]]
10
+ *
11
+ * * @param state
12
+ * @param config
13
+ * @param pc
14
+ * @returns {Function}
15
+ */
16
+ const brushExtents = (state, config, pc, events, brushGroup) => extents => {
17
+ const { brushes } = state;
18
+ const hiddenAxes = pc.hideAxis();
19
+
20
+ if (typeof extents === 'undefined') {
21
+ return Object.keys(config.dimensions)
22
+ .filter(d => !hiddenAxes.includes(d))
23
+ .reduce((acc, cur, pos) => {
24
+ const axisBrushes = brushes[cur];
25
+
26
+ if (axisBrushes === undefined || axisBrushes === null) {
27
+ acc[cur] = [];
28
+ } else {
29
+ acc[cur] = axisBrushes.reduce((d, p, i) => {
30
+ const raw = brushSelection(
31
+ document.getElementById('brush-' + pos + '-' + i)
32
+ );
33
+
34
+ if (raw) {
35
+ const yScale = config.dimensions[cur].yscale;
36
+ const scaled = invertByScale(raw, yScale);
37
+
38
+ d.push({
39
+ extent: p.brush.extent(),
40
+ selection: {
41
+ raw,
42
+ scaled,
43
+ },
44
+ });
45
+ }
46
+ return d;
47
+ }, []);
48
+ }
49
+
50
+ return acc;
51
+ }, {});
52
+ } else {
53
+ // //first get all the brush selections
54
+ // loop over each dimension and update appropriately (if it was passed in through extents)
55
+ Object.keys(config.dimensions).forEach((d, pos) => {
56
+ if (extents[d] === undefined || extents[d] === null) {
57
+ return;
58
+ }
59
+
60
+ const dim = config.dimensions[d];
61
+
62
+ const yExtents = extents[d].map(e => e.map(dim.yscale));
63
+
64
+ const _bs = yExtents.map((e, j) => {
65
+ const _brush = newBrush(state, config, pc, events, brushGroup)(
66
+ d,
67
+ select('#brush-group-' + pos)
68
+ );
69
+ //update the extent
70
+ //sets the brushable extent to the specified array of points [[x0, y0], [x1, y1]]
71
+ _brush.extent([[-15, e[1]], [15, e[0]]]);
72
+
73
+ return {
74
+ id: j,
75
+ brush: _brush,
76
+ ext: e,
77
+ };
78
+ });
79
+
80
+ brushes[d] = _bs;
81
+
82
+ drawBrushes(_bs, config, pc, d, select('#brush-group-' + pos));
83
+
84
+ //redraw the brush
85
+ //https://github.com/d3/d3-brush#brush_move
86
+ // For an x-brush, it must be defined as [x0, x1]; for a y-brush, it must be defined as [y0, y1].
87
+ _bs.forEach((f, k) => {
88
+ select('#brush-' + pos + '-' + k)
89
+ .call(f.brush)
90
+ .call(f.brush.move, f.ext.reverse());
91
+ });
92
+ });
93
+
94
+ //redraw the chart
95
+ pc.renderBrushed();
96
+
97
+ return pc;
98
+ }
99
+ };
100
+
101
+ export default brushExtents;
@@ -0,0 +1,13 @@
1
+ import newBrush from './newBrush';
2
+ import drawBrushes from './drawBrushes';
3
+
4
+ const brushFor = (state, config, pc, events, brushGroup) => (
5
+ axis,
6
+ _selector
7
+ ) => {
8
+ const { brushes } = state;
9
+ newBrush(state, config, pc, events, brushGroup)(axis, _selector);
10
+ drawBrushes(brushes[axis], config, pc, axis, _selector);
11
+ };
12
+
13
+ export default brushFor;
@@ -0,0 +1,53 @@
1
+ import { select } from 'd3-selection';
2
+ import { brushSelection } from 'd3-brush';
3
+
4
+ const brushReset = (state, config, pc) => dimension => {
5
+ const { brushes } = state;
6
+
7
+ if (dimension === undefined) {
8
+ if (pc.g() !== undefined && pc.g() !== null) {
9
+ Object.keys(config.dimensions).forEach((d, pos) => {
10
+ const axisBrush = brushes[d];
11
+
12
+ // hidden axes will be undefined
13
+ if (axisBrush) {
14
+ axisBrush.forEach((e, i) => {
15
+ const brush = document.getElementById('brush-' + pos + '-' + i);
16
+ if (brush && brushSelection(brush) !== null) {
17
+ pc.g()
18
+ .select('#brush-' + pos + '-' + i)
19
+ .call(e.brush.move, null);
20
+ }
21
+ });
22
+ }
23
+ });
24
+
25
+ pc.renderBrushed();
26
+ }
27
+ } else {
28
+ if (pc.g() !== undefined && pc.g() !== null) {
29
+ const axisBrush = brushes[dimension];
30
+ const pos = Object.keys(config.dimensions).indexOf(dimension);
31
+
32
+ if (axisBrush) {
33
+ axisBrush.forEach((e, i) => {
34
+ const brush = document.getElementById('brush-' + pos + '-' + i);
35
+ if (brushSelection(brush) !== null) {
36
+ pc.g()
37
+ .select('#brush-' + pos + '-' + i)
38
+ .call(e.brush.move, null);
39
+
40
+ if (typeof e.event === 'function') {
41
+ e.event(select('#brush-' + pos + '-' + i));
42
+ }
43
+ }
44
+ });
45
+ }
46
+
47
+ pc.renderBrushed();
48
+ }
49
+ }
50
+ return this;
51
+ };
52
+
53
+ export default brushReset;
@@ -0,0 +1,36 @@
1
+ import { select } from 'd3-selection';
2
+
3
+ const drawBrushes = (brushes, config, pc, axis, selector) => {
4
+ const brushSelection = selector.selectAll('.brush').data(brushes, d => d.id);
5
+
6
+ brushSelection
7
+ .enter()
8
+ .insert('g', '.brush')
9
+ .attr('class', 'brush')
10
+ .attr('dimension', axis)
11
+ .attr(
12
+ 'id',
13
+ b => 'brush-' + Object.keys(config.dimensions).indexOf(axis) + '-' + b.id
14
+ )
15
+ .each(function(brushObject) {
16
+ brushObject.brush(select(this));
17
+ });
18
+
19
+ brushSelection.each(function(brushObject) {
20
+ select(this)
21
+ .attr('class', 'brush')
22
+ .selectAll('.overlay')
23
+ .style('pointer-events', function() {
24
+ const brush = brushObject.brush;
25
+ if (brushObject.id === brushes.length - 1 && brush !== undefined) {
26
+ return 'all';
27
+ } else {
28
+ return 'none';
29
+ }
30
+ });
31
+ });
32
+
33
+ brushSelection.exit().remove();
34
+ };
35
+
36
+ export default drawBrushes;
@@ -0,0 +1,20 @@
1
+ import brushExtents from './brushExtents';
2
+ import install from './install';
3
+ import selected from './selected';
4
+ import uninstall from './uninstall';
5
+
6
+ const install1DMultiAxes = (brushGroup, config, pc, events) => {
7
+ const state = {
8
+ brushes: {},
9
+ brushNodes: {},
10
+ };
11
+
12
+ brushGroup.modes['1D-axes-multi'] = {
13
+ install: install(state, config, pc, events, brushGroup),
14
+ uninstall: uninstall(state, pc),
15
+ selected: selected(state, config, brushGroup),
16
+ brushState: brushExtents(state, config, pc),
17
+ };
18
+ };
19
+
20
+ export default install1DMultiAxes;
@@ -0,0 +1,29 @@
1
+ import { select } from 'd3-selection';
2
+ import brushExtents from './brushExtents';
3
+ import brushReset from './brushReset';
4
+ import brushFor from './brushFor';
5
+
6
+ const install = (state, config, pc, events, brushGroup) => () => {
7
+ if (!pc.g()) {
8
+ pc.createAxes();
9
+ }
10
+
11
+ const hiddenAxes = pc.hideAxis();
12
+
13
+ pc.g()
14
+ .append('svg:g')
15
+ .attr('id', (d, i) => 'brush-group-' + i)
16
+ .attr('class', 'brush-group')
17
+ .attr('dimension', d => d)
18
+ .each(function(d) {
19
+ if (!hiddenAxes.includes(d)) {
20
+ brushFor(state, config, pc, events, brushGroup)(d, select(this));
21
+ }
22
+ });
23
+
24
+ pc.brushExtents = brushExtents(state, config, pc, events, brushGroup);
25
+ pc.brushReset = brushReset(state, config, pc);
26
+ return pc;
27
+ };
28
+
29
+ export default install;
@@ -0,0 +1,102 @@
1
+ import { brushY, brushSelection } from 'd3-brush';
2
+ import { select } from 'd3-selection';
3
+ import drawBrushes from './drawBrushes';
4
+ import selected from './selected';
5
+
6
+ const brushUpdated = (config, pc, events) => newSelection => {
7
+ config.brushed = newSelection;
8
+ events.call('brush', pc, config.brushed);
9
+ pc.renderBrushed();
10
+ };
11
+
12
+ const newBrush = (state, config, pc, events, brushGroup) => (
13
+ axis,
14
+ _selector
15
+ ) => {
16
+ const { brushes, brushNodes } = state;
17
+
18
+ const brushRangeMax =
19
+ config.dimensions[axis].type === 'string'
20
+ ? config.dimensions[axis].yscale.range()[
21
+ config.dimensions[axis].yscale.range().length - 1
22
+ ]
23
+ : config.dimensions[axis].yscale.range()[0];
24
+
25
+ const brush = brushY().extent([[-15, 0], [15, brushRangeMax]]);
26
+ const id = brushes[axis] ? brushes[axis].length : 0;
27
+ const node =
28
+ 'brush-' + Object.keys(config.dimensions).indexOf(axis) + '-' + id;
29
+
30
+ if (brushes[axis]) {
31
+ brushes[axis].push({
32
+ id,
33
+ brush,
34
+ node,
35
+ });
36
+ } else {
37
+ brushes[axis] = [{ id, brush, node }];
38
+ }
39
+
40
+ if (brushNodes[axis]) {
41
+ brushNodes[axis].push({ id, node });
42
+ } else {
43
+ brushNodes[axis] = [{ id, node }];
44
+ }
45
+
46
+ brush
47
+ .on('start', function(event) {
48
+ if (event.sourceEvent !== null) {
49
+ events.call('brushstart', pc, config.brushed);
50
+ if (typeof event.sourceEvent.stopPropagation === 'function') {
51
+ event.sourceEvent.stopPropagation();
52
+ }
53
+ }
54
+ })
55
+ .on('brush', function() {
56
+ // record selections
57
+ brushUpdated(
58
+ config,
59
+ pc,
60
+ events
61
+ )(selected(state, config, pc, events, brushGroup));
62
+ })
63
+ .on('end', function(event) {
64
+ // Figure out if our latest brush has a selection
65
+ const lastBrushID = brushes[axis][brushes[axis].length - 1].id;
66
+ const lastBrush = document.getElementById(
67
+ 'brush-' +
68
+ Object.keys(config.dimensions).indexOf(axis) +
69
+ '-' +
70
+ lastBrushID
71
+ );
72
+ const selection = brushSelection(lastBrush);
73
+
74
+ if (
75
+ selection !== undefined &&
76
+ selection !== null &&
77
+ selection[0] !== selection[1]
78
+ ) {
79
+ newBrush(state, config, pc, events, brushGroup)(axis, _selector);
80
+
81
+ drawBrushes(brushes[axis], config, pc, axis, _selector);
82
+
83
+ brushUpdated(config, pc, events)(
84
+ selected(state, config, pc, events, brushGroup)
85
+ );
86
+ } else {
87
+ if (
88
+ event.sourceEvent &&
89
+ event.sourceEvent.toString() === '[object MouseEvent]' &&
90
+ event.selection === null
91
+ ) {
92
+ pc.brushReset(axis);
93
+ }
94
+ }
95
+
96
+ events.call('brushend', pc, config.brushed);
97
+ });
98
+
99
+ return brush;
100
+ };
101
+
102
+ export default newBrush;
@@ -0,0 +1,160 @@
1
+ import { brushSelection } from 'd3-brush';
2
+
3
+ // data within extents
4
+ const selected = (state, config, pc, events, brushGroup) => {
5
+ const { brushes } = state;
6
+
7
+ const is_brushed = (p, pos) => {
8
+ const axisBrushes = brushes[p];
9
+
10
+ for (let i = 0; i < axisBrushes.length; i++) {
11
+ const brush = document.getElementById('brush-' + pos + '-' + i);
12
+
13
+ if (brush && brushSelection(brush) !== null) {
14
+ return true;
15
+ }
16
+ }
17
+
18
+ return false;
19
+ };
20
+
21
+ const actives = Object.keys(config.dimensions).filter(is_brushed);
22
+ const extents = actives.map(p => {
23
+ const axisBrushes = brushes[p];
24
+
25
+ return axisBrushes
26
+ .filter(d => !pc.hideAxis().includes(d))
27
+ .map((d, i) =>
28
+ brushSelection(
29
+ document.getElementById(
30
+ 'brush-' + Object.keys(config.dimensions).indexOf(p) + '-' + i
31
+ )
32
+ )
33
+ )
34
+ .map((d, i) => {
35
+ if (d === null || d === undefined) {
36
+ return null;
37
+ } else if (typeof config.dimensions[p].yscale.invert === 'function') {
38
+ return [
39
+ config.dimensions[p].yscale.invert(d[1]),
40
+ config.dimensions[p].yscale.invert(d[0]),
41
+ ];
42
+ } else {
43
+ return d;
44
+ }
45
+ });
46
+ });
47
+
48
+ // We don't want to return the full data set when there are no axes brushed.
49
+ // Actually, when there are no axes brushed, by definition, no items are
50
+ // selected. So, let's avoid the filtering and just return false.
51
+ //if (actives.length === 0) return false;
52
+
53
+ // Resolves broken examples for now. They expect to get the full dataset back from empty brushes
54
+ if (actives.length === 0) return config.data;
55
+
56
+ // test if within range
57
+ const within = {
58
+ date: (d, p, i) => {
59
+ const dimExt = extents[i];
60
+
61
+ if (typeof config.dimensions[p].yscale.bandwidth === 'function') {
62
+ // if it is ordinal
63
+ for (const e of dimExt) {
64
+ if (e === null || e === undefined) {
65
+ continue;
66
+ }
67
+
68
+ if (
69
+ e[0] <= config.dimensions[p].yscale(d[p]) &&
70
+ config.dimensions[p].yscale(d[p]) <= e[1]
71
+ ) {
72
+ return true;
73
+ }
74
+ }
75
+
76
+ return false;
77
+ } else {
78
+ for (const e of dimExt) {
79
+ if (e === null || e === undefined) {
80
+ continue;
81
+ }
82
+
83
+ if (e[0] <= d[p] && d[p] <= e[1]) {
84
+ return true;
85
+ }
86
+ }
87
+
88
+ return false;
89
+ }
90
+ },
91
+ number: (d, p, i) => {
92
+ const dimExt = extents[i];
93
+
94
+ if (typeof config.dimensions[p].yscale.bandwidth === 'function') {
95
+ // if it is ordinal
96
+ for (const e of dimExt) {
97
+ if (e === null || e === undefined) {
98
+ continue;
99
+ }
100
+
101
+ if (
102
+ e[0] <= config.dimensions[p].yscale(d[p]) &&
103
+ config.dimensions[p].yscale(d[p]) <= e[1]
104
+ ) {
105
+ return true;
106
+ }
107
+ }
108
+
109
+ return false;
110
+ } else {
111
+ for (const e of dimExt) {
112
+ if (e === null || e === undefined) {
113
+ continue;
114
+ }
115
+
116
+ if (e[0] <= d[p] && d[p] <= e[1]) {
117
+ return true;
118
+ }
119
+ }
120
+
121
+ return false;
122
+ }
123
+ },
124
+ string: (d, p, i) => {
125
+ const dimExt = extents[i];
126
+
127
+ for (const e of dimExt) {
128
+ if (e === null || e === undefined) {
129
+ continue;
130
+ }
131
+
132
+ if (
133
+ e[0] <= config.dimensions[p].yscale(d[p]) &&
134
+ config.dimensions[p].yscale(d[p]) <= e[1]
135
+ ) {
136
+ return true;
137
+ }
138
+ }
139
+
140
+ return false;
141
+ },
142
+ };
143
+
144
+ return config.data.filter(d => {
145
+ switch (brushGroup.predicate) {
146
+ case 'AND':
147
+ return actives.every((p, i) =>
148
+ within[config.dimensions[p].type](d, p, i)
149
+ );
150
+ case 'OR':
151
+ return actives.some((p, i) =>
152
+ within[config.dimensions[p].type](d, p, i)
153
+ );
154
+ default:
155
+ throw new Error('Unknown brush predicate ' + config.brushPredicate);
156
+ }
157
+ });
158
+ };
159
+
160
+ export default selected;
@@ -0,0 +1,12 @@
1
+ const uninstall = (state, pc) => () => {
2
+ if (pc.g() !== undefined && pc.g() !== null)
3
+ pc.g()
4
+ .selectAll('.brush-group')
5
+ .remove();
6
+
7
+ state.brushes = {};
8
+ delete pc.brushExtents;
9
+ delete pc.brushReset;
10
+ };
11
+
12
+ export default uninstall;