@axdspub/axiom-charts 0.0.19 → 0.0.23

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.
@@ -1,11 +1,12 @@
1
1
  import { RequestItem } from '@axdspub/axiom-ui-data-services';
2
- import { extent, bisector, sum } from 'd3-array';
2
+ import { extent, sum } from 'd3-array';
3
3
  import { groupBy, debounce } from 'lodash';
4
4
  import { create } from 'd3-selection';
5
+ import * as d3 from 'd3';
6
+ import { bisector } from 'd3';
5
7
  import { scaleUtc, scaleLinear, scaleRadial } from 'd3-scale';
6
8
  import { axisLeft, axisBottom } from 'd3-axis';
7
9
  import { line, area, lineRadial, curveLinearClosed, pointRadial, areaRadial } from 'd3-shape';
8
- import * as d3 from 'd3';
9
10
 
10
11
  /******************************************************************************
11
12
  Copyright (c) Microsoft Corporation.
@@ -66,6 +67,10 @@ var EPlotTypes;
66
67
  class PlotRoot extends RequestItem {
67
68
  constructor(props) {
68
69
  super(props);
70
+ this.scrubSettingsDefaults = {
71
+ enabled: true,
72
+ axis: EChartAxes.x
73
+ };
69
74
  this.id = props.id;
70
75
  this.type = props.type;
71
76
  this.chart = props.chart;
@@ -74,6 +79,7 @@ class PlotRoot extends RequestItem {
74
79
  this.scrubbing = props.scrubbing;
75
80
  this.onDataLoad = props.onDataLoad;
76
81
  this.axisSettings = props.axisSettings;
82
+ this.scrubSettings = Object.assign(Object.assign({}, this.scrubSettingsDefaults), props.scrubSettings);
77
83
  this.runtime = {};
78
84
  }
79
85
  getAxisSetting(axis) {
@@ -167,12 +173,17 @@ class PlotRoot extends RequestItem {
167
173
  this.data = yield this.getData();
168
174
  });
169
175
  }
170
- drawScrubbing(mouseX) {
171
- console.log('drawScrubbing not implemented');
176
+ onLegendReady(legendItems) {
177
+ const chart = this.chart;
178
+ chart.emitPlotLegendReady(this.id, legendItems);
172
179
  }
173
- getScrubPosition(mouseX) {
174
- console.log('getScrubPosition not implemented');
175
- return undefined;
180
+ onScrub(scrubData) {
181
+ const chart = this.chart;
182
+ chart.emitPlotScrub(this.id, scrubData);
183
+ }
184
+ onScrubEnd() {
185
+ const chart = this.chart;
186
+ chart.emitPlotScrubEnd(this.id);
176
187
  }
177
188
  destroy() {
178
189
  }
@@ -184,8 +195,9 @@ class ChartRoot {
184
195
  this.settings = props.settings;
185
196
  this.element = props.element;
186
197
  this.onPlotDataLoad = props.onPlotDataLoad;
187
- this.onScrub = props.onScrub;
188
- this.onScrubEnd = props.onScrubEnd;
198
+ this.onPlotLegendReady = props.onPlotLegendReady;
199
+ this.onPlotScrub = props.onPlotScrub;
200
+ this.onPlotScrubEnd = props.onPlotScrubEnd;
189
201
  this.runtime = {
190
202
  prevWidth: 0,
191
203
  prevHeight: 0
@@ -201,6 +213,21 @@ class ChartRoot {
201
213
  })
202
214
  } */
203
215
  }
216
+ emitPlotLegendReady(plotId, legendItems) {
217
+ if (this.onPlotLegendReady === undefined)
218
+ return;
219
+ this.onPlotLegendReady(plotId, legendItems);
220
+ }
221
+ emitPlotScrub(plotId, scrubData) {
222
+ if (this.onPlotScrub === undefined)
223
+ return;
224
+ this.onPlotScrub(plotId, scrubData);
225
+ }
226
+ emitPlotScrubEnd(plotId) {
227
+ if (this.onPlotScrubEnd === undefined)
228
+ return;
229
+ this.onPlotScrubEnd(plotId);
230
+ }
204
231
  onError(e) {
205
232
  }
206
233
  onResize(prevWidth, prevHeight) {
@@ -412,10 +439,6 @@ class AxiomPlotRoot extends PlotRoot {
412
439
  }
413
440
 
414
441
  class AxiomLine extends AxiomPlotRoot {
415
- constructor() {
416
- super(...arguments);
417
- this.addedScrubbingListener = false;
418
- }
419
442
  getDomainAccessor(axis) {
420
443
  var _a, _b, _c;
421
444
  const accessors = ((_c = (_b = (_a = this.runtime) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.parsed) === null || _c === void 0 ? void 0 : _c.accessors) !== undefined ? this.runtime.data.parsed.accessors : {};
@@ -427,7 +450,10 @@ class AxiomLine extends AxiomPlotRoot {
427
450
  };
428
451
  }
429
452
  draw() {
430
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
453
+ const _super = Object.create(null, {
454
+ onLegendReady: { get: () => super.onLegendReady }
455
+ });
456
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
431
457
  return __awaiter(this, void 0, void 0, function* () {
432
458
  const style = this.style !== undefined ? this.style : {};
433
459
  if (this.parsedData === undefined) {
@@ -486,75 +512,49 @@ class AxiomLine extends AxiomPlotRoot {
486
512
  }
487
513
  line$1(this.parsedData);
488
514
  ctx.stroke();
515
+ if (((_m = this.axes) === null || _m === void 0 ? void 0 : _m.y) !== undefined) {
516
+ _super.onLegendReady.call(this, [{
517
+ id: this.axes.y.key,
518
+ label: (_o = chart.getAxisLabel(this.axes.y, 'y')) !== null && _o !== void 0 ? _o : this.axes.y.key,
519
+ style: { backgroundColor: ctx.strokeStyle }
520
+ }]);
521
+ }
522
+ this.setupScrubbing();
489
523
  });
490
524
  }
491
- getScrubPosition(mouseX) {
492
- if (this.xScale === undefined || this.yScale === undefined || this.parsedData === undefined || this.offset === undefined) {
493
- return undefined;
494
- }
495
- const xAccessor = this.getAccessorAtAxis('x');
496
- const yAccessor = this.getAccessorAtAxis('y');
497
- if (xAccessor === undefined || yAccessor === undefined) {
498
- return undefined;
499
- }
500
- const scrubValue = this.xScale.invert(mouseX - this.offset.x);
501
- const bisect = bisector((row) => xAccessor(row)).center;
502
- const bisectIndex = bisect(this.parsedData, scrubValue);
503
- const nearestRow = this.getNearestRow(bisectIndex, scrubValue, this.parsedData, xAccessor, yAccessor);
504
- const bisected = nearestRow;
505
- const xValue = xAccessor(bisected);
506
- const xPosition = this.xScale(xValue) + this.offset.x;
507
- const yValue = yAccessor(nearestRow);
508
- const yPosition = this.yScale(yValue) + this.offset.y;
509
- return {
510
- xPosition,
511
- xValue,
512
- yPosition,
513
- yValue
514
- };
515
- }
516
- getNearestRow(bisectIndex, scrubValue, parsedData, xAccessor, yAccessor) {
517
- const nonEmptyRows = parsedData.filter(row => yAccessor(row) !== null && yAccessor(row) !== undefined);
518
- let minDistance = Number.MAX_VALUE;
519
- let nearestRow = parsedData[bisectIndex];
520
- for (let i = 0; i < nonEmptyRows.length; i += 1) {
521
- const current = xAccessor(nonEmptyRows[i]);
522
- const distance = Math.abs(+current - +scrubValue);
523
- if (distance < minDistance) {
524
- minDistance = distance;
525
- nearestRow = nonEmptyRows[i];
526
- }
525
+ setupScrubbing() {
526
+ var _a, _b, _c;
527
+ const chartElements = this.chart.getChartElements();
528
+ if (chartElements !== undefined) {
529
+ (_a = chartElements.svg.node()) === null || _a === void 0 ? void 0 : _a.addEventListener('mouseover', event => { this.onMouseScrub(event); });
530
+ (_b = chartElements.svg.node()) === null || _b === void 0 ? void 0 : _b.addEventListener('mousemove', event => { this.onMouseScrub(event); });
531
+ (_c = chartElements.svg.node()) === null || _c === void 0 ? void 0 : _c.addEventListener('mouseleave', () => { this.onScrubEnd(); });
527
532
  }
528
- return nearestRow;
529
533
  }
530
- drawScrubbing(mouseX) {
534
+ onMouseScrub(event) {
531
535
  const chart = this.chart;
532
- const ctx = chart.getCanvasContext();
533
- if (ctx === null) {
534
- return undefined;
536
+ if (chart.onPlotScrub === undefined)
537
+ return;
538
+ const xAccessor = this.getAccessorAtAxis('x');
539
+ const yAccessor = this.getAccessorAtAxis('y');
540
+ if (this.scrubSettings.axis === undefined ||
541
+ this.xScale === undefined ||
542
+ this.yScale === undefined ||
543
+ xAccessor === undefined ||
544
+ yAccessor === undefined ||
545
+ this.parsedData === undefined ||
546
+ this.offset === undefined) {
547
+ return;
535
548
  }
536
- const scrubPosition = this.getScrubPosition(mouseX);
537
- if (scrubPosition === undefined)
549
+ const scrub = chart.getScrubEvent(event, this.scrubSettings.axis, this.xScale, this.yScale, xAccessor, yAccessor, this.parsedData, this.offset);
550
+ if (scrub === undefined || scrub.x === undefined)
538
551
  return;
539
- const { xPosition, yPosition } = scrubPosition;
540
- this.drawScrubCircle(xPosition, yPosition, ctx);
541
- this.drawScrubLine(xPosition, ctx);
542
- }
543
- drawScrubCircle(x, y, ctx) {
544
- ctx.beginPath();
545
- ctx.setLineDash([]);
546
- ctx.arc(x, y, 6, 0, 2 * Math.PI, true);
547
- ctx.strokeStyle = this.getStrokeStyle();
548
- ctx.lineWidth = this.getLineWidth();
549
- ctx.stroke();
550
- }
551
- drawScrubLine(x, ctx) {
552
- const lineHeight = this.chart.settings.height - this.chart.settings.margin.bottom;
553
- ctx.setLineDash([1, 1]);
554
- ctx.beginPath();
555
- ctx.moveTo(x, 0);
556
- ctx.lineTo(x, lineHeight);
557
- ctx.stroke();
552
+ this.onScrub(scrub);
553
+ chart.drawPlotScrubbing(this.id, scrub, this.style, this.scrubSettings);
554
+ }
555
+ onScrubEnd() {
556
+ this.chart.erasePlotScrub(this.id);
557
+ super.onScrubEnd();
558
558
  }
559
559
  getStrokeStyle() {
560
560
  const style = this.style !== undefined ? this.style : {};
@@ -605,7 +605,10 @@ class AxiomArea extends AxiomPlotRoot {
605
605
  };
606
606
  }
607
607
  draw() {
608
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
608
+ const _super = Object.create(null, {
609
+ onLegendReady: { get: () => super.onLegendReady }
610
+ });
611
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
609
612
  return __awaiter(this, void 0, void 0, function* () {
610
613
  const style = this.style !== undefined ? this.style : {};
611
614
  const data = yield this.getData();
@@ -673,18 +676,22 @@ class AxiomArea extends AxiomPlotRoot {
673
676
  ctx.beginPath();
674
677
  area$1(parsedData);
675
678
  ctx.fill();
679
+ if (((_m = this.axes) === null || _m === void 0 ? void 0 : _m.y) !== undefined) {
680
+ _super.onLegendReady.call(this, [{
681
+ id: this.axes.y.key,
682
+ label: (_o = chart.getAxisLabel(this.axes.y, 'y')) !== null && _o !== void 0 ? _o : this.axes.y.key,
683
+ style: { backgroundColor: ctx.fillStyle }
684
+ }]);
685
+ }
676
686
  });
677
687
  }
678
- drawScrubbing(mouseX) {
679
- console.error('AxiomArea.drawScrubbing not implemented');
680
- }
681
- getScrubPosition(mouseX) {
682
- console.error('AxiomArea.getScrubPosition not implemented');
683
- return undefined;
684
- }
685
688
  }
686
689
 
687
690
  class AxiomScatter extends AxiomPlotRoot {
691
+ constructor() {
692
+ super(...arguments);
693
+ this.circleClass = `${this.id}-scrub-circle`;
694
+ }
688
695
  getDomainAccessor(axis) {
689
696
  var _a, _b, _c;
690
697
  const accessors = ((_c = (_b = (_a = this.runtime) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.parsed) === null || _c === void 0 ? void 0 : _c.accessors) !== undefined ? this.runtime.data.parsed.accessors : {};
@@ -696,11 +703,14 @@ class AxiomScatter extends AxiomPlotRoot {
696
703
  };
697
704
  }
698
705
  draw() {
699
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
706
+ const _super = Object.create(null, {
707
+ onLegendReady: { get: () => super.onLegendReady }
708
+ });
709
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
700
710
  return __awaiter(this, void 0, void 0, function* () {
701
711
  const style = this.style !== undefined ? this.style : {};
702
712
  const data = yield this.getData();
703
- const parsedData = (_a = data === null || data === void 0 ? void 0 : data.parsed) === null || _a === void 0 ? void 0 : _a.data;
713
+ this.parsedData = (_a = data === null || data === void 0 ? void 0 : data.parsed) === null || _a === void 0 ? void 0 : _a.data;
704
714
  const xAccessor = this.getAccessorAtAxis('x');
705
715
  const yAccessor = this.getAccessorAtAxis('y');
706
716
  const chart = this.chart;
@@ -710,24 +720,28 @@ class AxiomScatter extends AxiomPlotRoot {
710
720
  }
711
721
  const xAxisScale = (_c = (_b = this === null || this === void 0 ? void 0 : this.axes) === null || _b === void 0 ? void 0 : _b.x) === null || _c === void 0 ? void 0 : _c.scale;
712
722
  const yAxisScale = (_e = (_d = this === null || this === void 0 ? void 0 : this.axes) === null || _d === void 0 ? void 0 : _d.y) === null || _e === void 0 ? void 0 : _e.scale;
713
- if (xAxisScale === undefined || yAxisScale === undefined || parsedData === undefined || xAccessor === undefined || yAccessor === undefined) {
723
+ if (xAxisScale === undefined || yAxisScale === undefined || this.parsedData === undefined || xAccessor === undefined || yAccessor === undefined) {
714
724
  return undefined;
715
725
  }
716
- const offset = {
726
+ this.offset = {
717
727
  x: ((_h = (_g = (_f = this === null || this === void 0 ? void 0 : this.axes) === null || _f === void 0 ? void 0 : _f.x) === null || _g === void 0 ? void 0 : _g.offset) === null || _h === void 0 ? void 0 : _h.x) !== undefined ? this.axes.x.offset.x : 0,
718
728
  y: ((_l = (_k = (_j = this === null || this === void 0 ? void 0 : this.axes) === null || _j === void 0 ? void 0 : _j.y) === null || _k === void 0 ? void 0 : _k.offset) === null || _l === void 0 ? void 0 : _l.y) !== undefined ? this.axes.y.offset.y : 0
719
729
  };
720
- const xScale = chart.getD3XScale(xAxisScale);
730
+ this.xScale = chart.getD3XScale(xAxisScale);
721
731
  const xPosition = (d) => {
732
+ if (this.xScale === undefined || this.offset === undefined)
733
+ return 0;
722
734
  const v = xAccessor(d);
723
- const p = xScale(v);
724
- return p === undefined ? 0 : (p + offset.x);
735
+ const p = this.xScale(v);
736
+ return p === undefined ? 0 : (p + this.offset.x);
725
737
  };
726
- const yScale = chart.getD3YScale(yAxisScale);
738
+ this.yScale = chart.getD3YScale(yAxisScale);
727
739
  const yPosition = (d) => {
740
+ if (this.yScale === undefined || this.offset === undefined)
741
+ return 0;
728
742
  const v = yAccessor(d);
729
- const p = yScale(v);
730
- return p === undefined ? 0 : (p + offset.y);
743
+ const p = this.yScale(v);
744
+ return p === undefined ? 0 : (p + this.offset.y);
731
745
  };
732
746
  const isDefined = (d) => {
733
747
  const v = yAccessor(d);
@@ -739,7 +753,7 @@ class AxiomScatter extends AxiomPlotRoot {
739
753
  const radius = style.radius !== undefined ? style.radius : 2;
740
754
  ctx.lineWidth = (style.strokeWidth !== undefined || style.strokeColor !== undefined) ? ((style.strokeWidth !== undefined ? style.strokeWidth : 1) + radius) : 0;
741
755
  ctx.fillStyle = style.fill !== undefined ? style.fill : '#666';
742
- parsedData.forEach(d => {
756
+ this.parsedData.forEach(d => {
743
757
  if (isDefined(d)) {
744
758
  ctx.beginPath();
745
759
  ctx.arc(xPosition(d), yPosition(d), radius, 0, 2 * Math.PI);
@@ -747,13 +761,52 @@ class AxiomScatter extends AxiomPlotRoot {
747
761
  ctx.fill();
748
762
  }
749
763
  });
764
+ if (((_m = this.axes) === null || _m === void 0 ? void 0 : _m.y) !== undefined) {
765
+ _super.onLegendReady.call(this, [{
766
+ id: this.axes.y.key,
767
+ label: (_o = chart.getAxisLabel(this.axes.y, 'y')) !== null && _o !== void 0 ? _o : this.axes.y.key,
768
+ style: {
769
+ backgroundColor: ctx.fillStyle,
770
+ border: `1px solid ${ctx.strokeStyle}`
771
+ }
772
+ }]);
773
+ }
774
+ this.setupScrubbing();
750
775
  });
751
776
  }
752
- getScrubPosition(mouseX) {
753
- throw new Error('Method not implemented.');
777
+ setupScrubbing() {
778
+ var _a, _b, _c;
779
+ const chartElements = this.chart.getChartElements();
780
+ if (chartElements !== undefined) {
781
+ (_a = chartElements.svg.node()) === null || _a === void 0 ? void 0 : _a.addEventListener('mouseover', event => { this.onMouseScrub(event); });
782
+ (_b = chartElements.svg.node()) === null || _b === void 0 ? void 0 : _b.addEventListener('mousemove', event => { this.onMouseScrub(event); });
783
+ (_c = chartElements.svg.node()) === null || _c === void 0 ? void 0 : _c.addEventListener('mouseleave', () => { this.onScrubEnd(); });
784
+ }
754
785
  }
755
- drawScrubbing(mouseX) {
756
- throw new Error('Method not implemented.');
786
+ onMouseScrub(event) {
787
+ const chart = this.chart;
788
+ if (chart.onPlotScrub === undefined)
789
+ return;
790
+ const xAccessor = this.getAccessorAtAxis('x');
791
+ const yAccessor = this.getAccessorAtAxis('y');
792
+ if (this.scrubSettings.axis === undefined ||
793
+ this.xScale === undefined ||
794
+ this.yScale === undefined ||
795
+ xAccessor === undefined ||
796
+ yAccessor === undefined ||
797
+ this.parsedData === undefined ||
798
+ this.offset === undefined) {
799
+ return;
800
+ }
801
+ const scrub = chart.getScrubEvent(event, this.scrubSettings.axis, this.xScale, this.yScale, xAccessor, yAccessor, this.parsedData, this.offset);
802
+ if (scrub === undefined || scrub.x === undefined)
803
+ return;
804
+ this.onScrub(scrub);
805
+ chart.drawPlotScrubbing(this.id, scrub, this.style, this.scrubSettings);
806
+ }
807
+ onScrubEnd() {
808
+ this.chart.erasePlotScrub(this.id);
809
+ super.onScrubEnd();
757
810
  }
758
811
  }
759
812
 
@@ -770,6 +823,9 @@ class AxiomBar extends AxiomPlotRoot {
770
823
  }
771
824
  }
772
825
  draw() {
826
+ const _super = Object.create(null, {
827
+ onLegendReady: { get: () => super.onLegendReady }
828
+ });
773
829
  var _a, _b, _c, _d, _e;
774
830
  return __awaiter(this, void 0, void 0, function* () {
775
831
  const dataResponse = yield this.getData();
@@ -815,9 +871,6 @@ class AxiomBar extends AxiomPlotRoot {
815
871
  // Colors
816
872
  const fillColors = (_e = (_d = this.style) === null || _d === void 0 ? void 0 : _d.colors) !== null && _e !== void 0 ? _e : d3.schemeTableau10;
817
873
  const color = d3.scaleOrdinal(fillColors).domain(subgroups);
818
- // TODO use real data
819
- // @ts-expect-error just for testing
820
- this.emitDataLoad(parsedData, color);
821
874
  const svg = chartElements.svg;
822
875
  const g = svg.insert('g');
823
876
  const x = this.getXScale(plotXStart, plotXEnd, groups);
@@ -828,24 +881,6 @@ class AxiomBar extends AxiomPlotRoot {
828
881
  .domain(subgroups)
829
882
  .range([0, x.bandwidth()])
830
883
  .padding(0.05);
831
- const onMouseEnterOrMove = (event, data) => {
832
- if (this.chart.onScrub === undefined)
833
- return;
834
- const scrubPositions = {
835
- [this.id]: {
836
- xPosition: event.offsetX,
837
- xValue: null,
838
- yPosition: event.offsetY,
839
- yValue: data.value
840
- }
841
- };
842
- this.chart.onScrub(scrubPositions);
843
- };
844
- const onMouseLeave = () => {
845
- if (this.chart.onScrubEnd === undefined)
846
- return;
847
- this.chart.onScrubEnd();
848
- };
849
884
  // Make Bar Groups
850
885
  g.append('g')
851
886
  .attr('width', plotWidth)
@@ -857,11 +892,12 @@ class AxiomBar extends AxiomPlotRoot {
857
892
  .attr('transform', d => `translate(${Number(x(xAccessor(d)))}, 0)`)
858
893
  .selectAll('rect')
859
894
  .data(d => Object.keys(this.dimensions).filter(key => key !== 'x').map((key) => {
860
- var _a, _b, _c;
895
+ var _a, _b, _c, _d, _e;
861
896
  return {
862
897
  label: (_a = this.dimensions[key].label) !== null && _a !== void 0 ? _a : key,
863
898
  key: (_b = this.dimensions[key].property) !== null && _b !== void 0 ? _b : '',
864
- value: d[(_c = this.dimensions[key].property) !== null && _c !== void 0 ? _c : '']
899
+ x: d[(_d = (_c = this.dimensions.x) === null || _c === void 0 ? void 0 : _c.property) !== null && _d !== void 0 ? _d : 'x'],
900
+ value: d[(_e = this.dimensions[key].property) !== null && _e !== void 0 ? _e : '']
865
901
  };
866
902
  }))
867
903
  .enter()
@@ -872,9 +908,9 @@ class AxiomBar extends AxiomPlotRoot {
872
908
  .attr('height', d => plotHeight - Number(subgroupScales[d.key](d.value)))
873
909
  .attr('fill', d => color(d.key))
874
910
  .classed('bar', true)
875
- .on('mouseover', onMouseEnterOrMove)
876
- .on('mousemove', onMouseEnterOrMove)
877
- .on('mouseleave', onMouseLeave);
911
+ .on('mouseover', (event, data) => { this.onMouseScrub(event, data); })
912
+ .on('mousemove', (event, data) => { this.onMouseScrub(event, data); })
913
+ .on('mouseleave', () => { this.onScrubEnd(); });
878
914
  // X Axis
879
915
  const xAxis = g.append('g')
880
916
  .attr('transform', `translate(0, ${plotHeight})`)
@@ -911,6 +947,28 @@ class AxiomBar extends AxiomPlotRoot {
911
947
  .attr('font-weight', 800)
912
948
  .text(y2Label);
913
949
  }
950
+ _super.onLegendReady.call(this, Object.keys(this.dimensions).filter(key => key !== 'x').map(key => {
951
+ var _a, _b;
952
+ return ({
953
+ id: key,
954
+ label: (_a = this.dimensions[key].label) !== null && _a !== void 0 ? _a : key,
955
+ style: { backgroundColor: this.dimensions[key].property === undefined ? '' : color((_b = this.dimensions[key].property) !== null && _b !== void 0 ? _b : '') }
956
+ });
957
+ }));
958
+ });
959
+ }
960
+ onMouseScrub(event, data) {
961
+ if (this.chart.onPlotScrub === undefined)
962
+ return;
963
+ this.onScrub({
964
+ x: {
965
+ position: event.offsetX,
966
+ value: data.x
967
+ },
968
+ y: {
969
+ position: event.offsetY,
970
+ value: data.value
971
+ }
914
972
  });
915
973
  }
916
974
  getXScale(plotXStart, plotXEnd, groups) {
@@ -949,26 +1007,6 @@ class AxiomBar extends AxiomPlotRoot {
949
1007
  }
950
1008
  return subgroupScales;
951
1009
  }
952
- getScrubPosition(mouseX) { return undefined; }
953
- drawScrubbing(mouseX) { }
954
- emitDataLoad(data, color) {
955
- if (this.onDataLoad !== undefined) {
956
- const legend = Object.keys(this.dimensions).filter(key => key !== 'x').map(key => {
957
- var _a, _b;
958
- return ({
959
- key,
960
- label: (_a = this.dimensions[key].label) !== null && _a !== void 0 ? _a : key,
961
- color: color((_b = this.dimensions[key].property) !== null && _b !== void 0 ? _b : '')
962
- });
963
- });
964
- const barPlotLoadEvent = {
965
- plotId: this.id,
966
- data,
967
- properties: { legend }
968
- };
969
- this.onDataLoad(barPlotLoadEvent);
970
- }
971
- }
972
1010
  }
973
1011
 
974
1012
  const chartTypes = {
@@ -1101,13 +1139,15 @@ class AxiomChart extends ChartRoot {
1101
1139
  axisSelection.append('g').call(axisG);
1102
1140
  }
1103
1141
  });
1104
- this.showYLabels(axes, this.plots);
1142
+ if (this.settings.layout === 'timeseries') {
1143
+ this.showYLabelsForTimeSeries(axes, this.plots);
1144
+ }
1105
1145
  }
1106
1146
  getAxisLabel(axis, dimensionKey) {
1107
1147
  var _a;
1108
1148
  return (_a = axis.plots[0]) === null || _a === void 0 ? void 0 : _a.dimensions[dimensionKey].label;
1109
1149
  }
1110
- showYLabels(axes, plots) {
1150
+ showYLabelsForTimeSeries(axes, plots) {
1111
1151
  const yLabelsAreSupportedForPlotType = [EPlotTypes.line, EPlotTypes.scatter, EPlotTypes.seasonal, EPlotTypes.area]
1112
1152
  .find(type => type === plots[0].type) !== undefined;
1113
1153
  if (plots.length === 0 || !yLabelsAreSupportedForPlotType) {
@@ -1202,7 +1242,8 @@ class AxiomChart extends ChartRoot {
1202
1242
  .attr('viewBox', [0, 0, width, height])
1203
1243
  .attr('width', width)
1204
1244
  .attr('height', height)
1205
- .style('position', 'absolute');
1245
+ .style('position', 'absolute')
1246
+ .style('z-index', 20);
1206
1247
  const canvas = create('canvas')
1207
1248
  .attr('width', width)
1208
1249
  .attr('height', height)
@@ -1219,6 +1260,128 @@ class AxiomChart extends ChartRoot {
1219
1260
  }
1220
1261
  return this.chartElements;
1221
1262
  }
1263
+ drawPlotScrubbing(plotId, scrubPosition, style, scrubSettings) {
1264
+ const chartElements = this.getChartElements();
1265
+ if (chartElements === undefined)
1266
+ return;
1267
+ if (scrubPosition === undefined || scrubPosition.x === undefined || scrubPosition.y === undefined)
1268
+ return;
1269
+ const { x, y } = scrubPosition;
1270
+ this.drawScrubLine(plotId, scrubPosition, chartElements.svg, style, scrubSettings);
1271
+ this.drawPlotScrubCircle(plotId, x === null || x === void 0 ? void 0 : x.position, y === null || y === void 0 ? void 0 : y.position, chartElements.svg, style);
1272
+ }
1273
+ drawScrubLine(plotId, scrubPosition, svg, style, scrubSettings) {
1274
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1275
+ const scrubLineClass = this.getPlotScrubLineClass(plotId);
1276
+ svg.select(`.${scrubLineClass}`).remove();
1277
+ const line = svg.insert('line')
1278
+ .classed(scrubLineClass, true);
1279
+ if ((scrubSettings === null || scrubSettings === void 0 ? void 0 : scrubSettings.axis) === EChartAxes.x) {
1280
+ const lineLength = this.settings.height - this.settings.margin.bottom;
1281
+ line.attr('x1', (_b = (_a = scrubPosition.x) === null || _a === void 0 ? void 0 : _a.position) !== null && _b !== void 0 ? _b : 0)
1282
+ .attr('y1', 0)
1283
+ .attr('x2', (_d = (_c = scrubPosition.x) === null || _c === void 0 ? void 0 : _c.position) !== null && _d !== void 0 ? _d : 0)
1284
+ .attr('y2', lineLength)
1285
+ .attr('stroke', this.getPlotStrokeColor(style))
1286
+ .style('stroke-width', this.getPlotStrokeWidth(style));
1287
+ }
1288
+ else {
1289
+ const width = this.getChartWidth();
1290
+ const left = this.settings.margin.left;
1291
+ const lineLength = width - left;
1292
+ line.attr('x1', this.settings.margin.left)
1293
+ .attr('y1', (_f = (_e = scrubPosition.y) === null || _e === void 0 ? void 0 : _e.position) !== null && _f !== void 0 ? _f : 0)
1294
+ .attr('x2', width + lineLength)
1295
+ .attr('y2', (_h = (_g = scrubPosition.y) === null || _g === void 0 ? void 0 : _g.position) !== null && _h !== void 0 ? _h : 0)
1296
+ .attr('stroke', this.getPlotStrokeColor(style))
1297
+ .style('stroke-width', this.getPlotStrokeWidth(style));
1298
+ }
1299
+ }
1300
+ drawPlotScrubCircle(plotId, x, y, svg, style) {
1301
+ svg.select(`.${this.getPlotScrubCircleClass(plotId)}`).remove();
1302
+ svg.insert('circle')
1303
+ .classed(this.getPlotScrubCircleClass(plotId), true)
1304
+ .attr('r', 6)
1305
+ .attr('cx', x)
1306
+ .attr('cy', y)
1307
+ .style('stroke', this.getPlotStrokeColor(style))
1308
+ .style('stroke-width', this.getPlotStrokeWidth(style))
1309
+ .style('fill-opacity', '0');
1310
+ }
1311
+ erasePlotScrub(plotId) {
1312
+ if (this.chartElements === undefined)
1313
+ return;
1314
+ this.chartElements.svg.select(`.${this.getPlotScrubCircleClass(plotId)}`).remove();
1315
+ this.chartElements.svg.select(`.${this.getPlotScrubLineClass(plotId)}`).remove();
1316
+ }
1317
+ getScrubEvent(event, scrubAxis, xScale, yScale, xAccessor, yAccessor, rows, offsetSettings) {
1318
+ let mousePosition;
1319
+ let offset;
1320
+ let scrubbingScale;
1321
+ let scrubbingAccessor;
1322
+ let valueAccessor;
1323
+ if (scrubAxis === EChartAxes.x) {
1324
+ mousePosition = event.offsetX;
1325
+ offset = offsetSettings.x;
1326
+ scrubbingScale = xScale;
1327
+ scrubbingAccessor = xAccessor;
1328
+ valueAccessor = yAccessor;
1329
+ }
1330
+ else {
1331
+ mousePosition = event.offsetY;
1332
+ offset = offsetSettings.y;
1333
+ scrubbingScale = yScale;
1334
+ scrubbingAccessor = yAccessor;
1335
+ valueAccessor = xAccessor;
1336
+ }
1337
+ const scrubValue = scrubbingScale.invert(mousePosition - offset);
1338
+ const bisect = bisector((row) => scrubbingAccessor(row)).center;
1339
+ const bisectIndex = bisect(rows, scrubValue);
1340
+ const nearestRow = this.getDataRowNearestToScrub(bisectIndex, scrubValue, rows, valueAccessor, scrubbingAccessor);
1341
+ const bisected = nearestRow;
1342
+ const xValue = xAccessor(bisected);
1343
+ const xPosition = xScale(xValue) + offsetSettings.x;
1344
+ const yValue = yAccessor(nearestRow);
1345
+ const yPosition = yScale(yValue) + offsetSettings.y;
1346
+ return {
1347
+ x: {
1348
+ position: xPosition,
1349
+ value: xValue
1350
+ },
1351
+ y: {
1352
+ position: yPosition,
1353
+ value: yValue
1354
+ }
1355
+ };
1356
+ }
1357
+ getDataRowNearestToScrub(bisectIndex, scrubValue, parsedData, valueAccessor, scrubbingAccessor) {
1358
+ const nonEmptyRows = parsedData.filter(row => valueAccessor(row) !== null && valueAccessor(row) !== undefined);
1359
+ let minDistance = Number.MAX_VALUE;
1360
+ let nearestRow = parsedData[bisectIndex];
1361
+ for (let i = 0; i < nonEmptyRows.length; i += 1) {
1362
+ const current = scrubbingAccessor(nonEmptyRows[i]);
1363
+ const distance = Math.abs(+current - +scrubValue);
1364
+ if (distance < minDistance) {
1365
+ minDistance = distance;
1366
+ nearestRow = nonEmptyRows[i];
1367
+ }
1368
+ }
1369
+ return nearestRow;
1370
+ }
1371
+ getPlotStrokeColor(style) {
1372
+ var _a;
1373
+ return (_a = style === null || style === void 0 ? void 0 : style.strokeColor) !== null && _a !== void 0 ? _a : '#333';
1374
+ }
1375
+ getPlotStrokeWidth(style) {
1376
+ var _a;
1377
+ return (_a = style === null || style === void 0 ? void 0 : style.strokeWidth) !== null && _a !== void 0 ? _a : 1;
1378
+ }
1379
+ getPlotScrubCircleClass(plotId) {
1380
+ return `${plotId}-scrub-circle`;
1381
+ }
1382
+ getPlotScrubLineClass(plotId) {
1383
+ return `${plotId}-scrub-line`;
1384
+ }
1222
1385
  attachChartElements() {
1223
1386
  const chartElements = this.getChartElements();
1224
1387
  if (this.element !== undefined && chartElements !== undefined) {
@@ -1231,7 +1394,6 @@ class AxiomChart extends ChartRoot {
1231
1394
  this.element.append(canvasNode);
1232
1395
  }
1233
1396
  }
1234
- this.addScrubbing();
1235
1397
  }
1236
1398
  createPlot(plot) {
1237
1399
  const props = this.getPlotImplementationProps(plot);
@@ -1255,67 +1417,6 @@ class AxiomChart extends ChartRoot {
1255
1417
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
1256
1418
  }
1257
1419
  }
1258
- addScrubbing() {
1259
- const ctx = this.getCanvasContext();
1260
- if (ctx === null) {
1261
- return;
1262
- }
1263
- ctx.canvas.addEventListener('touchmove', event => {
1264
- const touch = event.touches[0];
1265
- const touchOffset = 20; // TODO: figure out why touch.clientX is always off to the right
1266
- this.onScrubTriggered(touch.clientX - touchOffset);
1267
- });
1268
- ctx.canvas.addEventListener('touchend', event => { this.onScrubEndTriggered(); });
1269
- ctx.canvas.addEventListener('mousemove', event => { this.onScrubTriggered(event.offsetX); });
1270
- ctx.canvas.addEventListener('mouseleave', event => { this.onScrubEndTriggered(); });
1271
- }
1272
- onScrubTriggered(cursorX) {
1273
- if (this.plotImplementations === undefined)
1274
- return;
1275
- const plotsWithScrubbingEnabled = this.plotImplementations.filter(plot => {
1276
- return plot.scrubbing !== undefined && plot.scrubbing && plot.type === EPlotTypes.line;
1277
- });
1278
- const plotScrubPositions = this.getScrubPositions(cursorX, plotsWithScrubbingEnabled);
1279
- if (this.onScrub !== undefined) {
1280
- this.onScrub(plotScrubPositions);
1281
- }
1282
- this.runtime.busy = true;
1283
- this.clearCanvas();
1284
- const drawPromises = this.plotImplementations.map((plot) => __awaiter(this, void 0, void 0, function* () { yield plot.draw(); }));
1285
- Promise.all(drawPromises).then(() => {
1286
- plotsWithScrubbingEnabled.forEach(plot => {
1287
- const position = plotScrubPositions[plot.id];
1288
- plot.drawScrubbing(position.xPosition);
1289
- });
1290
- this.runtime.busy = false;
1291
- }).catch(error => {
1292
- console.error(error);
1293
- });
1294
- }
1295
- onScrubEndTriggered() {
1296
- this.removeScrubbers();
1297
- if (this.onScrubEnd !== undefined) {
1298
- this.onScrubEnd();
1299
- }
1300
- }
1301
- removeScrubbers() {
1302
- if (this.plotImplementations === undefined)
1303
- return;
1304
- this.runtime.busy = true;
1305
- this.clearCanvas();
1306
- const drawPromises = this.plotImplementations.map((plot) => __awaiter(this, void 0, void 0, function* () { yield plot.draw(); }));
1307
- void Promise.all(drawPromises);
1308
- }
1309
- getScrubPositions(mouseX, plots) {
1310
- const plotScrubPositions = {};
1311
- plots.forEach(plot => {
1312
- const scrubPosition = plot.getScrubPosition(mouseX);
1313
- if (scrubPosition !== undefined) {
1314
- plotScrubPositions[plot.id] = scrubPosition;
1315
- }
1316
- });
1317
- return plotScrubPositions;
1318
- }
1319
1420
  init(drawImmediately = false) {
1320
1421
  const _super = Object.create(null, {
1321
1422
  init: { get: () => super.init }
@@ -1334,7 +1435,10 @@ class AxiomChart extends ChartRoot {
1334
1435
 
1335
1436
  class AxiomRadialLine extends AxiomLine {
1336
1437
  draw() {
1337
- var _a, _b, _c, _d, _e;
1438
+ const _super = Object.create(null, {
1439
+ onLegendReady: { get: () => super.onLegendReady }
1440
+ });
1441
+ var _a, _b, _c, _d, _e, _f, _g;
1338
1442
  return __awaiter(this, void 0, void 0, function* () {
1339
1443
  const style = this.style !== undefined ? this.style : {};
1340
1444
  const data = yield this.getData();
@@ -1378,21 +1482,32 @@ class AxiomRadialLine extends AxiomLine {
1378
1482
  .curve(curveLinearClosed);
1379
1483
  const radialData = parsedData.slice();
1380
1484
  const chartOffset = chart.getChartOffset();
1485
+ const stroke = style.strokeColor !== undefined ? style.strokeColor : '#333';
1381
1486
  svg.append('g')
1382
1487
  .attr('transform', `translate(${chartOffset.x},${chartOffset.y})`)
1383
1488
  .attr('class', 'radial-line')
1384
1489
  .append('path')
1385
1490
  .attr('fill', 'none')
1386
- .attr('stroke', style.strokeColor !== undefined ? style.strokeColor : '#333')
1491
+ .attr('stroke', stroke)
1387
1492
  .attr('stroke-width', style.strokeWidth !== undefined ? style.strokeWidth : 1)
1388
1493
  .attr('d', line(radialData));
1494
+ if (((_f = this.axes) === null || _f === void 0 ? void 0 : _f.y) !== undefined) {
1495
+ _super.onLegendReady.call(this, [{
1496
+ id: this.axes.y.key,
1497
+ label: (_g = chart.getAxisLabel(this.axes.y, 'y')) !== null && _g !== void 0 ? _g : this.axes.y.key,
1498
+ style: { backgroundColor: stroke }
1499
+ }]);
1500
+ }
1389
1501
  });
1390
1502
  }
1391
1503
  }
1392
1504
 
1393
1505
  class AxiomRadialScatter extends AxiomLine {
1394
1506
  draw() {
1395
- var _a, _b, _c, _d, _e;
1507
+ const _super = Object.create(null, {
1508
+ onLegendReady: { get: () => super.onLegendReady }
1509
+ });
1510
+ var _a, _b, _c, _d, _e, _f, _g;
1396
1511
  return __awaiter(this, void 0, void 0, function* () {
1397
1512
  // const style = this.style !== undefined ? this.style : {}
1398
1513
  const data = yield this.getData();
@@ -1431,23 +1546,38 @@ class AxiomRadialScatter extends AxiomLine {
1431
1546
  .attr('class', 'radial-scatter');
1432
1547
  const style = this.style !== undefined ? this.style : {};
1433
1548
  const radius = style.radius !== undefined ? style.radius : 2;
1549
+ const fill = style.fill !== undefined ? style.fill : '#333';
1550
+ const stroke = style.strokeColor !== undefined ? style.strokeColor : '#CCC';
1434
1551
  parsedData.forEach(d => {
1435
1552
  const pt = pointRadial(xPosition(d), yPosition(d));
1436
1553
  g.append('circle')
1437
1554
  .attr('r', radius * 2)
1438
- .attr('fill', style.fill !== undefined ? style.fill : '#333')
1439
- .attr('stroke', style.strokeColor !== undefined ? style.strokeColor : '#CCC')
1555
+ .attr('fill', fill)
1556
+ .attr('stroke', stroke)
1440
1557
  .attr('stroke-width', (style.strokeWidth !== undefined || style.strokeColor !== undefined) ? ((style.strokeWidth !== undefined ? style.strokeWidth : 1)) : 0)
1441
1558
  .attr('cx', pt[0] + chart.settings.margin.left)
1442
1559
  .attr('cy', pt[1] + chart.settings.margin.top);
1443
1560
  });
1561
+ if (((_f = this.axes) === null || _f === void 0 ? void 0 : _f.y) !== undefined) {
1562
+ _super.onLegendReady.call(this, [{
1563
+ id: this.axes.y.key,
1564
+ label: (_g = chart.getAxisLabel(this.axes.y, 'y')) !== null && _g !== void 0 ? _g : this.axes.y.key,
1565
+ style: {
1566
+ backgroundColor: fill,
1567
+ border: `1px solid ${stroke}`
1568
+ }
1569
+ }]);
1570
+ }
1444
1571
  });
1445
1572
  }
1446
1573
  }
1447
1574
 
1448
1575
  class AxiomRadialArea extends AxiomArea {
1449
1576
  draw() {
1450
- var _a, _b, _c, _d, _e;
1577
+ const _super = Object.create(null, {
1578
+ onLegendReady: { get: () => super.onLegendReady }
1579
+ });
1580
+ var _a, _b, _c, _d, _e, _f, _g;
1451
1581
  return __awaiter(this, void 0, void 0, function* () {
1452
1582
  const style = this.style !== undefined ? this.style : {};
1453
1583
  const data = yield this.getData();
@@ -1502,21 +1632,172 @@ class AxiomRadialArea extends AxiomArea {
1502
1632
  .curve(curveLinearClosed);
1503
1633
  const radialData = parsedData.slice();
1504
1634
  const chartOffset = chart.getChartOffset();
1635
+ const fill = style.fill !== undefined ? style.fill : '#EDEDED99';
1505
1636
  svg.insert('g', 'g.axis')
1506
1637
  .attr('transform', `translate(${chartOffset.x},${chartOffset.y})`)
1507
1638
  .attr('class', 'radial-area')
1508
1639
  .append('path')
1509
- .attr('fill', style.fill !== undefined ? style.fill : '#EDEDED99')
1640
+ .attr('fill', fill)
1510
1641
  .attr('stroke-width', style.strokeWidth !== undefined ? style.strokeWidth : 1)
1511
1642
  .attr('d', area(radialData));
1643
+ if (((_f = this.axes) === null || _f === void 0 ? void 0 : _f.y) !== undefined) {
1644
+ _super.onLegendReady.call(this, [{
1645
+ id: this.axes.y.key,
1646
+ label: (_g = chart.getAxisLabel(this.axes.y, 'y')) !== null && _g !== void 0 ? _g : this.axes.y.key,
1647
+ style: { backgroundColor: fill }
1648
+ }]);
1649
+ }
1512
1650
  });
1513
1651
  }
1514
- drawScrubbing(mouseX) {
1515
- console.error('AxiomRadialArea.drawScrubbing not implemented');
1652
+ }
1653
+
1654
+ class AxiomRadialRose extends AxiomPlotRoot {
1655
+ constructor() {
1656
+ super(...arguments);
1657
+ this.data = undefined;
1658
+ this.numBins = 16;
1659
+ this.speedBins = d3.range(1, 8, 1);
1660
+ this.stacks = undefined;
1516
1661
  }
1517
- getScrubPosition(mouseX) {
1518
- console.error('AxiomRadialArea.getScrubPosition not implemented');
1519
- return undefined;
1662
+ setStackedData() {
1663
+ var _a, _b;
1664
+ return __awaiter(this, void 0, void 0, function* () {
1665
+ let parsedData = [];
1666
+ if (this.data === undefined) {
1667
+ this.data = yield this.getData();
1668
+ parsedData = (_b = (_a = this.data.parsed) === null || _a === void 0 ? void 0 : _a.data) !== null && _b !== void 0 ? _b : [];
1669
+ }
1670
+ if (this.stacks === undefined) {
1671
+ this.stacks = this.getStackedData(parsedData);
1672
+ }
1673
+ });
1674
+ }
1675
+ getDomain(_axis) {
1676
+ return __awaiter(this, void 0, void 0, function* () {
1677
+ yield this.setStackedData();
1678
+ if (this.stacks === undefined)
1679
+ return [0, 10];
1680
+ return [0, this.getMaxStackTotal(this.stacks)];
1681
+ });
1682
+ }
1683
+ getStackedData(parsedData) {
1684
+ const degreesPerBin = 360 / this.numBins;
1685
+ const directionBins = d3.range(0, 360, degreesPerBin);
1686
+ const speedBins = this.speedBins;
1687
+ const stacks = [];
1688
+ directionBins.forEach(direction => {
1689
+ const newBin = {
1690
+ minDirection: direction
1691
+ };
1692
+ speedBins.forEach(bin => { newBin[bin] = 0; });
1693
+ stacks.push(newBin);
1694
+ });
1695
+ parsedData.forEach(row => {
1696
+ const directionBinIndex = Math.floor(row.direction / degreesPerBin);
1697
+ const stack = stacks[directionBinIndex];
1698
+ if (row.speed < speedBins[speedBins.length - 1]) {
1699
+ const speedBin = Math.floor(row.speed);
1700
+ stack[speedBin] += 1;
1701
+ }
1702
+ });
1703
+ return stacks;
1704
+ }
1705
+ getMaxStackTotal(stacks) {
1706
+ var _a;
1707
+ return (_a = d3.max(stacks, stack => {
1708
+ return this.speedBins.reduce((sum, current) => sum + stack[current], 0);
1709
+ })) !== null && _a !== void 0 ? _a : 0;
1710
+ }
1711
+ draw() {
1712
+ const _super = Object.create(null, {
1713
+ onLegendReady: { get: () => super.onLegendReady }
1714
+ });
1715
+ var _a, _b, _c, _d, _e, _f;
1716
+ return __awaiter(this, void 0, void 0, function* () {
1717
+ yield this.setStackedData();
1718
+ if (this.stacks === undefined || this.speedBins === undefined)
1719
+ return;
1720
+ const xAccessors = this.getAccessorsAtAxis('x');
1721
+ const xAccessor = this.getAccessorAtAxis('x');
1722
+ const x0Accessor = xAccessors.x0;
1723
+ const x1Accessor = xAccessors.x1;
1724
+ const yAccessors = this.getAccessorsAtAxis('y');
1725
+ const yAccessor = this.getAccessorAtAxis('y');
1726
+ const y0Accessor = yAccessors.y0;
1727
+ const y1Accessor = yAccessors.y1;
1728
+ const chart = this.chart;
1729
+ const chartElements = chart.getChartElements();
1730
+ if (chartElements === undefined || chartElements.svg === null) {
1731
+ return undefined;
1732
+ }
1733
+ const svg = chartElements.svg;
1734
+ const xAxisScale = (_b = (_a = this === null || this === void 0 ? void 0 : this.axes) === null || _a === void 0 ? void 0 : _a.x) === null || _b === void 0 ? void 0 : _b.scale;
1735
+ const yAxisScale = (_d = (_c = this === null || this === void 0 ? void 0 : this.axes) === null || _c === void 0 ? void 0 : _c.y) === null || _d === void 0 ? void 0 : _d.scale;
1736
+ if (xAxisScale === undefined ||
1737
+ yAxisScale === undefined ||
1738
+ (xAccessor === undefined && x0Accessor === undefined && x1Accessor === undefined) ||
1739
+ (yAccessor === undefined && y0Accessor === undefined && y1Accessor === undefined)) {
1740
+ console.log('Missing one of: xAxisScale, yAxisScale, parsedData, xAccessor(s), yAccessor(s)');
1741
+ return undefined;
1742
+ }
1743
+ const maxStackTotal = this.getMaxStackTotal(this.stacks);
1744
+ const xScale = d3.scaleBand()
1745
+ .domain(d3.range(0, 360, 360 / this.numBins))
1746
+ .range([0, 2 * Math.PI]);
1747
+ const yScale = d3.scaleRadial()
1748
+ .domain([0, maxStackTotal])
1749
+ .range([chart.getInnerRadius(), chart.getOuterRadius()]);
1750
+ const fillColors = (_f = (_e = this.style) === null || _e === void 0 ? void 0 : _e.colors) !== null && _f !== void 0 ? _f : d3.schemeTableau10;
1751
+ const zScale = d3
1752
+ .scaleOrdinal()
1753
+ .range(fillColors);
1754
+ const data = d3.stack().keys(this.speedBins.map(bin => String(bin)))(this.stacks);
1755
+ const chartOffset = chart.getChartOffset();
1756
+ const bandwidth = 2 * Math.PI / this.numBins;
1757
+ svg.insert('g', 'g.axis')
1758
+ .attr('transform', `translate(${chartOffset.x},${chartOffset.y})`)
1759
+ .selectAll('g')
1760
+ .data(data)
1761
+ .enter().append('g')
1762
+ .attr('fill', (d) => zScale(d.key))
1763
+ .selectAll('path')
1764
+ .data(d => d)
1765
+ .enter().append('path')
1766
+ .on('mouseover', (event, data) => { this.onMouseScrub(event, data); })
1767
+ .on('mousemove', (event, data) => { this.onMouseScrub(event, data); })
1768
+ .on('mouseleave', () => { this.onScrubEnd(); })
1769
+ .attr('d', d3.arc()
1770
+ .innerRadius(d => yScale(d[0]))
1771
+ .outerRadius(d => yScale(d[1]))
1772
+ .startAngle(d => { var _a; return ((_a = xScale(d.data.minDirection)) !== null && _a !== void 0 ? _a : 0) - (bandwidth / 2); })
1773
+ .endAngle(d => { var _a; return ((_a = xScale(d.data.minDirection)) !== null && _a !== void 0 ? _a : 0) + bandwidth / 2; })
1774
+ .padAngle(0.01)
1775
+ .padRadius(chart.getInnerRadius()));
1776
+ _super.onLegendReady.call(this, data.map((d, i) => {
1777
+ var _a, _b;
1778
+ return ({
1779
+ id: d.key,
1780
+ label: `< ${this.speedBins[i]} ${(_b = (_a = this.dimensions.z.displayUnits) === null || _a === void 0 ? void 0 : _a.label) !== null && _b !== void 0 ? _b : ''}`,
1781
+ style: {
1782
+ backgroundColor: zScale(d.key)
1783
+ }
1784
+ });
1785
+ }));
1786
+ });
1787
+ }
1788
+ onMouseScrub(event, data) {
1789
+ if (this.chart.onPlotScrub === undefined)
1790
+ return;
1791
+ this.onScrub({
1792
+ x: {
1793
+ position: event.offsetX,
1794
+ value: data.data.angle
1795
+ },
1796
+ y: {
1797
+ position: event.offsetY,
1798
+ value: Object.assign({}, data)
1799
+ }
1800
+ });
1520
1801
  }
1521
1802
  }
1522
1803
 
@@ -1617,6 +1898,7 @@ class AxiomRadialChart extends AxiomChart {
1617
1898
  return this.getChartOffset();
1618
1899
  }
1619
1900
  getXAxis(axis, _axisSettings) {
1901
+ var _a, _b, _c;
1620
1902
  if (axis.scale === undefined) {
1621
1903
  return g => g;
1622
1904
  }
@@ -1627,7 +1909,7 @@ class AxiomRadialChart extends AxiomChart {
1627
1909
  const tickFormat = d3Scale.tickFormat();
1628
1910
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1629
1911
  // @ts-expect-error
1630
- const ticks = d3Scale.ticks().map(tickFormat);
1912
+ const ticks = (_c = (_b = (_a = this.settings.axes) === null || _a === void 0 ? void 0 : _a.x) === null || _b === void 0 ? void 0 : _b.ticks) !== null && _c !== void 0 ? _c : d3Scale.ticks().map(tickFormat);
1631
1913
  const rotateOffset = -90;
1632
1914
  const getRotate = (index, len) => {
1633
1915
  const r = (index * 360 / len);
@@ -1653,6 +1935,7 @@ class AxiomRadialChart extends AxiomChart {
1653
1935
  .attr('x1', -5)
1654
1936
  .attr('x2', outerRadius - innerRadius + 10))
1655
1937
  .call(g => g.append('text')
1938
+ .attr('text-anchor', 'middle')
1656
1939
  .attr('transform', 'rotate(90)translate(0,16)')
1657
1940
  .text((d) => d)));
1658
1941
  return g;
@@ -1670,553 +1953,10 @@ class AxiomRadialChart extends AxiomChart {
1670
1953
  else if (plot.type === 'area') {
1671
1954
  return new AxiomRadialArea(props);
1672
1955
  }
1673
- return new AxiomRadialLine(props);
1674
- }
1675
- }
1676
-
1677
- var Direction;
1678
- (function (Direction) {
1679
- Direction["N"] = "N";
1680
- Direction["NNE"] = "NNE";
1681
- Direction["NE"] = "NE";
1682
- Direction["ENE"] = "ENE";
1683
- Direction["E"] = "E";
1684
- Direction["ESE"] = "ESE";
1685
- Direction["SE"] = "SE";
1686
- Direction["SSE"] = "SSE";
1687
- Direction["S"] = "S";
1688
- Direction["SSW"] = "SSW";
1689
- Direction["SW"] = "SW";
1690
- Direction["WSW"] = "WSW";
1691
- Direction["W"] = "W";
1692
- Direction["WNW"] = "WNW";
1693
- Direction["NW"] = "NW";
1694
- Direction["NNW"] = "NNW";
1695
- })(Direction || (Direction = {}));
1696
-
1697
- const DEFAULT_COLUMNS = ['angle', '0-1', '1-2', '2-3', '3-4', '4-5', '5-6', '6-7', '7+'];
1698
- function classifyDir(direction) {
1699
- const dTh = 11.25;
1700
- let dir;
1701
- if (direction >= 360 - dTh || direction < dTh) {
1702
- dir = Direction.N;
1703
- }
1704
- else if (direction >= dTh && direction < dTh * 3) {
1705
- dir = Direction.NNE;
1706
- }
1707
- else if (direction >= dTh * 3 && direction < dTh * 5) {
1708
- dir = Direction.NE;
1709
- }
1710
- else if (direction >= dTh * 5 && direction < dTh * 7) {
1711
- dir = Direction.ENE;
1712
- }
1713
- else if (direction >= dTh * 7 && direction < dTh * 9) {
1714
- dir = Direction.E;
1715
- }
1716
- else if (direction >= dTh * 9 && direction < dTh * 11) {
1717
- dir = Direction.ESE;
1718
- }
1719
- else if (direction >= dTh * 11 && direction < dTh * 13) {
1720
- dir = Direction.SE;
1721
- }
1722
- else if (direction >= dTh * 13 && direction < dTh * 15) {
1723
- dir = Direction.SSE;
1724
- }
1725
- else if (direction >= dTh * 15 && direction < dTh * 17) {
1726
- dir = Direction.S;
1727
- }
1728
- else if (direction >= dTh * 17 && direction < dTh * 19) {
1729
- dir = Direction.SSW;
1730
- }
1731
- else if (direction >= dTh * 19 && direction < dTh * 21) {
1732
- dir = Direction.SW;
1733
- }
1734
- else if (direction >= dTh * 21 && direction < dTh * 23) {
1735
- dir = Direction.WSW;
1736
- }
1737
- else if (direction >= dTh * 23 && direction < dTh * 25) {
1738
- dir = Direction.W;
1739
- }
1740
- else if (direction >= dTh * 25 && direction < dTh * 27) {
1741
- dir = Direction.WNW;
1742
- }
1743
- else if (direction >= dTh * 27 && direction < dTh * 29) {
1744
- dir = Direction.NW;
1745
- }
1746
- else if (direction >= dTh * 29 && direction < dTh * 31) {
1747
- dir = Direction.NNW;
1748
- }
1749
- else {
1750
- throw new Error('over 360 or under 0');
1751
- }
1752
- return dir;
1753
- }
1754
- function getNewCounts() {
1755
- return {
1756
- N: {
1757
- '0-1': 0,
1758
- '1-2': 0,
1759
- '2-3': 0,
1760
- '3-4': 0,
1761
- '4-5': 0,
1762
- '5-6': 0,
1763
- '6-7': 0,
1764
- '7+': 0
1765
- },
1766
- NNE: {
1767
- '0-1': 0,
1768
- '1-2': 0,
1769
- '2-3': 0,
1770
- '3-4': 0,
1771
- '4-5': 0,
1772
- '5-6': 0,
1773
- '6-7': 0,
1774
- '7+': 0
1775
- },
1776
- NE: {
1777
- '0-1': 0,
1778
- '1-2': 0,
1779
- '2-3': 0,
1780
- '3-4': 0,
1781
- '4-5': 0,
1782
- '5-6': 0,
1783
- '6-7': 0,
1784
- '7+': 0
1785
- },
1786
- ENE: {
1787
- '0-1': 0,
1788
- '1-2': 0,
1789
- '2-3': 0,
1790
- '3-4': 0,
1791
- '4-5': 0,
1792
- '5-6': 0,
1793
- '6-7': 0,
1794
- '7+': 0
1795
- },
1796
- E: {
1797
- '0-1': 0,
1798
- '1-2': 0,
1799
- '2-3': 0,
1800
- '3-4': 0,
1801
- '4-5': 0,
1802
- '5-6': 0,
1803
- '6-7': 0,
1804
- '7+': 0
1805
- },
1806
- ESE: {
1807
- '0-1': 0,
1808
- '1-2': 0,
1809
- '2-3': 0,
1810
- '3-4': 0,
1811
- '4-5': 0,
1812
- '5-6': 0,
1813
- '6-7': 0,
1814
- '7+': 0
1815
- },
1816
- SE: {
1817
- '0-1': 0,
1818
- '1-2': 0,
1819
- '2-3': 0,
1820
- '3-4': 0,
1821
- '4-5': 0,
1822
- '5-6': 0,
1823
- '6-7': 0,
1824
- '7+': 0
1825
- },
1826
- SSE: {
1827
- '0-1': 0,
1828
- '1-2': 0,
1829
- '2-3': 0,
1830
- '3-4': 0,
1831
- '4-5': 0,
1832
- '5-6': 0,
1833
- '6-7': 0,
1834
- '7+': 0
1835
- },
1836
- S: {
1837
- '0-1': 0,
1838
- '1-2': 0,
1839
- '2-3': 0,
1840
- '3-4': 0,
1841
- '4-5': 0,
1842
- '5-6': 0,
1843
- '6-7': 0,
1844
- '7+': 0
1845
- },
1846
- SSW: {
1847
- '0-1': 0,
1848
- '1-2': 0,
1849
- '2-3': 0,
1850
- '3-4': 0,
1851
- '4-5': 0,
1852
- '5-6': 0,
1853
- '6-7': 0,
1854
- '7+': 0
1855
- },
1856
- SW: {
1857
- '0-1': 0,
1858
- '1-2': 0,
1859
- '2-3': 0,
1860
- '3-4': 0,
1861
- '4-5': 0,
1862
- '5-6': 0,
1863
- '6-7': 0,
1864
- '7+': 0
1865
- },
1866
- WSW: {
1867
- '0-1': 0,
1868
- '1-2': 0,
1869
- '2-3': 0,
1870
- '3-4': 0,
1871
- '4-5': 0,
1872
- '5-6': 0,
1873
- '6-7': 0,
1874
- '7+': 0
1875
- },
1876
- W: {
1877
- '0-1': 0,
1878
- '1-2': 0,
1879
- '2-3': 0,
1880
- '3-4': 0,
1881
- '4-5': 0,
1882
- '5-6': 0,
1883
- '6-7': 0,
1884
- '7+': 0
1885
- },
1886
- WNW: {
1887
- '0-1': 0,
1888
- '1-2': 0,
1889
- '2-3': 0,
1890
- '3-4': 0,
1891
- '4-5': 0,
1892
- '5-6': 0,
1893
- '6-7': 0,
1894
- '7+': 0
1895
- },
1896
- NW: {
1897
- '0-1': 0,
1898
- '1-2': 0,
1899
- '2-3': 0,
1900
- '3-4': 0,
1901
- '4-5': 0,
1902
- '5-6': 0,
1903
- '6-7': 0,
1904
- '7+': 0
1905
- },
1906
- NNW: {
1907
- '0-1': 0,
1908
- '1-2': 0,
1909
- '2-3': 0,
1910
- '3-4': 0,
1911
- '4-5': 0,
1912
- '5-6': 0,
1913
- '6-7': 0,
1914
- '7+': 0
1915
- }
1916
- };
1917
- }
1918
- function countPush(count, dir, speed) {
1919
- if (speed < 1) {
1920
- count[dir]['0-1'] = count[dir]['0-1'] + 1;
1921
- }
1922
- else if (speed < 2) {
1923
- count[dir]['1-2'] = count[dir]['1-2'] + 1;
1924
- }
1925
- else if (speed < 3) {
1926
- count[dir]['2-3'] = count[dir]['2-3'] + 1;
1927
- }
1928
- else if (speed < 4) {
1929
- count[dir]['3-4'] = count[dir]['3-4'] + 1;
1930
- }
1931
- else if (speed < 5) {
1932
- count[dir]['5-6'] = count[dir]['5-6'] + 1;
1933
- }
1934
- else if (speed < 6) {
1935
- count[dir]['6-7'] = count[dir]['6-7'] + 1;
1936
- }
1937
- else {
1938
- count[dir]['7+'] = count[dir]['7+'] + 1;
1939
- }
1940
- }
1941
- function calculateWindRoseFrequency(data) {
1942
- // const dataLength = data.direction.length
1943
- const count = getNewCounts();
1944
- data.direction.map((direction, index) => {
1945
- const speed = data.speed[index];
1946
- const dir = classifyDir(direction);
1947
- countPush(count, dir, speed);
1948
- return null;
1949
- });
1950
- const ret = Object.keys(count).map((key) => {
1951
- let total = 0;
1952
- const elements = Object.keys(count[key]).map((subkey) => {
1953
- // const E = count[key as Direction][subkey as SubKey] / data.direction.length
1954
- const E = count[key][subkey];
1955
- total += E;
1956
- return { [subkey]: E };
1957
- });
1958
- const obj = {};
1959
- elements.map((val) => {
1960
- const [elKey] = Object.keys(val);
1961
- const [elVal] = Object.values(val);
1962
- obj[elKey] = elVal;
1963
- return obj;
1964
- });
1965
- return Object.assign(Object.assign({ angle: key }, obj), { total });
1966
- });
1967
- return ret;
1968
- }
1969
- function calculateWindRoseProportions(data) {
1970
- const frequency = calculateWindRoseFrequency(data);
1971
- frequency.forEach(direction => {
1972
- Object.keys(direction).forEach(key => {
1973
- if (key === 'angle' || key === 'total')
1974
- return;
1975
- direction[key] = direction[key] / direction.total;
1976
- });
1977
- });
1978
- return frequency;
1979
- }
1980
-
1981
- /* eslint-disable @typescript-eslint/ban-ts-comment */
1982
- class AxiomWindrose extends AxiomPlotRoot {
1983
- constructor(props) {
1984
- super(props);
1985
- this.Y_DOMAIN_TYPE = 'frequency';
1986
- this.raw = {
1987
- direction: [],
1988
- speed: []
1989
- };
1990
- this.columns = DEFAULT_COLUMNS;
1991
- const chart = this.chart;
1992
- const chartElements = chart.getChartElements();
1993
- if ((chartElements === null || chartElements === void 0 ? void 0 : chartElements.svg) !== undefined) {
1994
- chartElements.svg.style('z-index', 20);
1995
- // TODO find better way ^. Doing this so that svg can get events.
1996
- }
1997
- }
1998
- initializeData() {
1999
- if (this.Y_DOMAIN_TYPE === 'frequency') {
2000
- return calculateWindRoseFrequency(this.raw);
2001
- }
2002
- else {
2003
- return calculateWindRoseProportions(this.raw);
1956
+ else if (plot.type === 'windrose') {
1957
+ return new AxiomRadialRose(props);
2004
1958
  }
2005
- }
2006
- draw() {
2007
- var _a, _b, _c, _d, _e;
2008
- return __awaiter(this, void 0, void 0, function* () {
2009
- const chart = this.chart;
2010
- const chartElements = chart.getChartElements();
2011
- if (chartElements === undefined || chartElements.svg === null) {
2012
- return undefined;
2013
- }
2014
- let { width, height } = chart.settings;
2015
- width = Number(width);
2016
- height = Number(height);
2017
- const { margin } = chart.settings;
2018
- const innerRadius = 20;
2019
- const chartWidth = width - margin.left - margin.right;
2020
- const chartHeight = height - margin.top - margin.bottom;
2021
- const legendGap = 10;
2022
- const outerRadius = Math.min(chartWidth, chartHeight) / 2.4 - legendGap / 2;
2023
- this.raw = {
2024
- direction: [],
2025
- speed: []
2026
- };
2027
- this.runtime.data.parsed.data.forEach((row) => {
2028
- this.raw.direction.push(row.direction);
2029
- this.raw.speed.push(row.speed);
2030
- });
2031
- const data = this.initializeData();
2032
- if (this.g !== undefined) {
2033
- this.g.remove();
2034
- }
2035
- const svg = chartElements.svg;
2036
- const g = svg
2037
- .insert('g')
2038
- .attr('transform', `translate(${width / 2},${height / 2})`);
2039
- this.g = g;
2040
- const angle = d3.scaleLinear().range([0, 2 * Math.PI]);
2041
- const radius = d3.scaleLinear().range([innerRadius, outerRadius]);
2042
- const x = d3
2043
- .scaleBand()
2044
- .range([0, 2 * Math.PI])
2045
- .align(0);
2046
- const y = d3
2047
- .scaleLinear() // you can try scaleRadial but it scales differently
2048
- .range([innerRadius, outerRadius]);
2049
- const fillColors = (_b = (_a = this.style) === null || _a === void 0 ? void 0 : _a.colors) !== null && _b !== void 0 ? _b : d3.schemeTableau10;
2050
- const z = d3
2051
- .scaleOrdinal()
2052
- .range(fillColors);
2053
- x.domain(data.map((d) => String(d.angle)));
2054
- if (this.Y_DOMAIN_TYPE === 'frequency') {
2055
- y.domain([
2056
- 0,
2057
- ((_c = d3.max(data, (d) => d.total)) !== null && _c !== void 0 ? _c : 0) > 1
2058
- ? (_d = d3.max(data, (d) => d.total)) !== null && _d !== void 0 ? _d : 0
2059
- : 1
2060
- ]);
2061
- }
2062
- else if (this.Y_DOMAIN_TYPE === 'proportion') {
2063
- y.domain([0, 1]);
2064
- }
2065
- z.domain(this.columns.slice(1));
2066
- // Extend the domain slightly to match the range of [0, 2π].
2067
- angle.domain([0, (_e = d3.max(data, (_, i) => i + 1)) !== null && _e !== void 0 ? _e : 0]);
2068
- // radius.domain([0, d3.max(data, (): number => 0) || 0])
2069
- radius.domain([0, 0]);
2070
- // radius.domain([innerRadius, outerRadius]);
2071
- const angleOffset = -360.0 / data.length / 2.0;
2072
- // @ts-expect-error
2073
- const stackGen = d3
2074
- .stack()
2075
- .keys(this.columns.slice(1));
2076
- const arcVal = d3 // d3.DefaultArcObject
2077
- .arc()
2078
- // @ts-expect-error
2079
- .innerRadius((d) => Number(y(d[0])))
2080
- // @ts-expect-error
2081
- .outerRadius((d) => Number(y(d[1])))
2082
- // @ts-expect-error
2083
- .startAngle((d) => Number(x(d.data.angle)))
2084
- // .startAngle((d) => x(String(d.startAngle)) || 0)
2085
- // @ts-expect-error
2086
- .endAngle((d) => Number(x(d.data.angle)) + x.bandwidth())
2087
- // .endAngle((d) => x(String(d.endAngle)) || 0 + x.bandwidth())
2088
- .padAngle(0.0)
2089
- .padRadius(innerRadius);
2090
- const arcParent = g
2091
- .append('g')
2092
- .selectAll('g')
2093
- // @ts-expect-error
2094
- .data(stackGen(data))
2095
- .enter()
2096
- .append('g')
2097
- .attr('fill', (d) => {
2098
- return z(d.key);
2099
- });
2100
- // @ts-expect-error
2101
- const arc = arcParent
2102
- .selectAll('path')
2103
- .data((d) => d)
2104
- .enter()
2105
- .append('path');
2106
- arc
2107
- // @ts-expect-error
2108
- .attr('d', arcVal)
2109
- .attr('transform', `rotate(${angleOffset})`)
2110
- .on('mouseover', (event, data) => { this.onMouseEnterOrMove(event, data); })
2111
- .on('mousemove', (event, data) => { this.onMouseEnterOrMove(event, data); })
2112
- .on('mouseleave', () => { this.onMouseLeave(); });
2113
- const label = g
2114
- .append('g')
2115
- .selectAll('g')
2116
- .data(data)
2117
- .enter()
2118
- .append('g')
2119
- .attr('text-anchor', 'middle')
2120
- .attr('transform', (d) => {
2121
- return `rotate(${((Number(x(d.angle)) + x.bandwidth() / 2) * 180) / Math.PI -
2122
- (90 - angleOffset)})translate(${outerRadius + 30},0)`;
2123
- });
2124
- label
2125
- .append('text')
2126
- // eslint-disable-next-line no-confusing-arrow
2127
- .attr('transform', (d, _i) => {
2128
- var _a;
2129
- // @ts-expect-error
2130
- return (!Number.isNaN((((_a = x(d.angle)) !== null && _a !== void 0 ? _a : 0 + x.bandwidth() / 2 + Math.PI / 2) % (2 * Math.PI < Math.PI))))
2131
- ? 'rotate(90)translate(0,16)'
2132
- : 'rotate(-90)translate(0,-9)';
2133
- })
2134
- .attr('transform', 'rotate(90)translate(0,-9)')
2135
- .text((d) => d.angle)
2136
- .style('font-size', 14);
2137
- g.selectAll('.axis')
2138
- .data(d3.range(angle.domain()[1]))
2139
- .enter()
2140
- .append('g')
2141
- .attr('class', 'axis')
2142
- .attr('transform', (d) => `rotate(${(angle(d) * 180) / Math.PI})`)
2143
- .call(d3
2144
- // @ts-expect-error
2145
- .axisLeft()
2146
- // @ts-expect-error
2147
- .scale(radius.copy().range([-innerRadius, -(outerRadius + 10)])));
2148
- const yAxis = g.append('g').attr('text-anchor', 'middle');
2149
- const yTick = yAxis
2150
- .selectAll('g')
2151
- .data(y.ticks(5).slice(1))
2152
- .enter()
2153
- .append('g');
2154
- yTick
2155
- .append('circle')
2156
- .attr('fill', 'none')
2157
- .attr('stroke', 'gray')
2158
- .attr('stroke-dasharray', '4,4')
2159
- .attr('r', y);
2160
- yTick
2161
- .append('text')
2162
- .attr('y', (d) => -y(d))
2163
- .attr('dy', '-0.35em')
2164
- .attr('x', () => -10)
2165
- .text(y.tickFormat(5, 's'))
2166
- .style('font-size', 14);
2167
- const legend = g
2168
- .append('g')
2169
- .selectAll('g')
2170
- .data(this.columns.slice(1).reverse())
2171
- .enter()
2172
- .append('g')
2173
- .attr('transform', (d, i) => `translate(${outerRadius + 45 + legendGap / 2},${-outerRadius + 40 + (i - (this.columns.length - 1) / 2) * 20})`);
2174
- legend
2175
- .append('rect')
2176
- .attr('width', 18)
2177
- .attr('height', 18)
2178
- // @ts-expect-error
2179
- .attr('fill', z);
2180
- legend
2181
- .append('text')
2182
- .attr('x', -24)
2183
- .attr('y', 9)
2184
- .attr('dy', '0.35em')
2185
- .text((d) => d)
2186
- .style('font-size', 12);
2187
- g.exit().remove();
2188
- });
2189
- }
2190
- getScrubPosition(mouseX) {
2191
- return undefined;
2192
- }
2193
- drawScrubbing(mouseX) {
2194
- }
2195
- onMouseEnterOrMove(event, data) {
2196
- if (this.chart.onScrub === undefined)
2197
- return;
2198
- const scrubPositions = {
2199
- [this.id]: {
2200
- xPosition: event.offsetX,
2201
- xValue: data.data.angle,
2202
- yPosition: event.offsetY,
2203
- yValue: data[1] - data[0],
2204
- properties: Object.assign({}, data)
2205
- }
2206
- };
2207
- this.chart.onScrub(scrubPositions);
2208
- }
2209
- onMouseLeave() {
2210
- if (this.chart.onScrubEnd === undefined)
2211
- return;
2212
- this.chart.onScrubEnd();
2213
- }
2214
- }
2215
-
2216
- class AxiomWindroseChart extends AxiomChart {
2217
- createPlot(plot) {
2218
- const props = this.getPlotImplementationProps(plot);
2219
- return new AxiomWindrose(props);
1959
+ return new AxiomRadialLine(props);
2220
1960
  }
2221
1961
  }
2222
1962
 
@@ -2255,7 +1995,6 @@ const axiomPlotTypes = Object.assign(Object.assign({}, plotsOb), { line: AxiomLi
2255
1995
  const axiomLibrary = {
2256
1996
  Chart: AxiomChart,
2257
1997
  RadialChart: AxiomRadialChart,
2258
- WindroseChart: AxiomWindroseChart,
2259
1998
  plotTypes: axiomPlotTypes
2260
1999
  };
2261
2000