From 2740d833077720fe0be0240fe7bda4b2cc790208 Mon Sep 17 00:00:00 2001 From: Patrik Kullman Date: Sun, 4 Apr 2021 22:56:57 +0200 Subject: [PATCH 1/7] feat: isolate d3js compatility layers Enable es module users to specify d3js compatibility layer while maintaining dynamic adaptation to run-time d3js version for UMD users. --- src/base/base-mixin.js | 4 +- src/base/bubble-mixin.js | 4 +- src/base/coordinate-grid-mixin.js | 6 +-- src/charts/bar-chart.js | 6 +-- src/charts/box-plot.js | 4 +- src/charts/bubble-chart.js | 4 +- src/charts/bubble-overlay.js | 8 ++-- src/charts/cbox-menu.js | 6 +-- src/charts/data-grid.js | 4 +- src/charts/data-table.js | 4 +- src/charts/geo-choropleth-chart.js | 4 +- src/charts/heatmap.js | 8 ++-- src/charts/html-legend.js | 10 ++--- src/charts/legend.js | 14 +++---- src/charts/pie-chart.js | 16 ++++---- src/charts/row-chart.js | 14 +++---- src/charts/select-menu.js | 4 +- src/charts/series-chart.js | 4 +- src/charts/sunburst-chart.js | 6 +-- src/core/config.js | 11 ++++++ src/core/d3compat-v5.js | 27 +++++++++++++ src/core/d3compat-v6.js | 32 +++++++++++++++ src/core/d3compat.js | 61 ----------------------------- src/index-with-version.js | 2 + src/index.js | 1 - web-src/examples/filter-stacks.html | 2 +- 26 files changed, 138 insertions(+), 128 deletions(-) create mode 100644 src/core/d3compat-v5.js create mode 100644 src/core/d3compat-v6.js delete mode 100644 src/core/d3compat.js diff --git a/src/base/base-mixin.js b/src/base/base-mixin.js index e16b4d7b31..dd73d8f7d4 100644 --- a/src/base/base-mixin.js +++ b/src/base/base-mixin.js @@ -11,7 +11,7 @@ import {logger} from '../core/logger'; import {printers} from '../core/printers'; import {InvalidStateException} from '../core/invalid-state-exception'; import {BadArgumentException} from '../core/bad-argument-exception'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; const _defaultFilterHandler = (dimension, filters) => { if (filters.length === 0) { @@ -723,7 +723,7 @@ export class BaseMixin { .attr('tabindex', 0); if (onClickFunction) { - tabElements.on('keydown', adaptHandler((d, event) => { + tabElements.on('keydown', config._d3compat.eventHandler((d, event) => { // trigger only if d is an object undestood by KeyAccessor() if (event.keyCode === 13 && typeof d === 'object') { onClickFunction.call(this, d, ...onClickArgs) diff --git a/src/base/bubble-mixin.js b/src/base/bubble-mixin.js index f23d25c736..6a03cacfbf 100644 --- a/src/base/bubble-mixin.js +++ b/src/base/bubble-mixin.js @@ -4,7 +4,7 @@ import { scaleLinear } from 'd3-scale'; import {ColorMixin} from './color-mixin'; import {transition} from '../core/core'; import {events} from '../core/events'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; /** * This Mixin provides reusable functionalities for any chart that needs to visualize data using bubbles. @@ -156,7 +156,7 @@ export const BubbleMixin = Base => class extends ColorMixin(Base) { label = bubbleGEnter.append('text') .attr('text-anchor', 'middle') .attr('dy', '.3em') - .on('click', adaptHandler(d => this.onClick(d))); + .on('click', config._d3compat.eventHandler(d => this.onClick(d))); } label diff --git a/src/base/coordinate-grid-mixin.js b/src/base/coordinate-grid-mixin.js index 7a77c1db52..c8d6c459ca 100644 --- a/src/base/coordinate-grid-mixin.js +++ b/src/base/coordinate-grid-mixin.js @@ -12,7 +12,7 @@ import {optionalTransition, transition} from '../core/core'; import {units} from '../core/units'; import {constants} from '../core/constants'; import {utils} from '../core/utils'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; import {logger} from '../core/logger'; import {filters} from '../core/filters'; import {events} from '../core/events'; @@ -78,7 +78,7 @@ export class CoordinateGridMixin extends ColorMixin(MarginMixin) { this._zoomScale = [1, Infinity]; this._zoomOutRestrict = true; - this._zoom = zoom().on('zoom', adaptHandler((d, evt) => this._onZoom(evt))); + this._zoom = zoom().on('zoom', config._d3compat.eventHandler((d, evt) => this._onZoom(evt))); this._nullZoom = zoom().on('zoom', null); this._hasBeenMouseZoomable = false; this._ignoreZoomEvents = false; // ignore when carrying out programmatic zoom operations @@ -969,7 +969,7 @@ export class CoordinateGridMixin extends ColorMixin(MarginMixin) { renderBrush (g, doTransition) { if (this._brushOn) { - this._brush.on('start brush end', adaptHandler((d, evt) => this._brushing(evt))); + this._brush.on('start brush end', config._d3compat.eventHandler((d, evt) => this._brushing(evt))); // To retrieve selection we need self._gBrush this._gBrush = g.append('g') diff --git a/src/charts/bar-chart.js b/src/charts/bar-chart.js index 8448c0255d..fb9d014243 100644 --- a/src/charts/bar-chart.js +++ b/src/charts/bar-chart.js @@ -5,7 +5,7 @@ import {transition} from '../core/core'; import {constants} from '../core/constants'; import {logger} from '../core/logger'; import {pluck, utils} from '../core/utils'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; const MIN_BAR_WIDTH = 1; const DEFAULT_GAP_BETWEEN_BARS = 2; @@ -145,7 +145,7 @@ export class BarChart extends StackMixin { .merge(labels); if (this.isOrdinal()) { - labelsEnterUpdate.on('click', adaptHandler(d => this.onClick(d))); + labelsEnterUpdate.on('click', config._d3compat.eventHandler(d => this.onClick(d))); labelsEnterUpdate.attr('cursor', 'pointer'); } @@ -190,7 +190,7 @@ export class BarChart extends StackMixin { } if (this.isOrdinal()) { - barsEnterUpdate.on('click', adaptHandler(d => this.onClick(d))); + barsEnterUpdate.on('click', config._d3compat.eventHandler(d => this.onClick(d))); } if (this._keyboardAccessible) { diff --git a/src/charts/box-plot.js b/src/charts/box-plot.js index 454f32f16f..1620461f1c 100644 --- a/src/charts/box-plot.js +++ b/src/charts/box-plot.js @@ -7,7 +7,7 @@ import {CoordinateGridMixin} from '../base/coordinate-grid-mixin'; import {transition} from '../core/core'; import {units} from '../core/units'; import {utils} from '../core/utils'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; // Returns a function to compute the interquartile range. function defaultWhiskersIQR (k) { @@ -198,7 +198,7 @@ export class BoxPlot extends CoordinateGridMixin { .classed('dc-tabbable', this._keyboardAccessible) .attr('transform', (d, i) => this._boxTransform(d, i)) .call(this._box) - .on('click', adaptHandler(d => { + .on('click', config._d3compat.eventHandler(d => { this.filter(this.keyAccessor()(d)); this.redrawGroup(); })) diff --git a/src/charts/bubble-chart.js b/src/charts/bubble-chart.js index 9cb44eaa2b..1fa9135d14 100644 --- a/src/charts/bubble-chart.js +++ b/src/charts/bubble-chart.js @@ -1,7 +1,7 @@ import {BubbleMixin} from '../base/bubble-mixin'; import {CoordinateGridMixin} from '../base/coordinate-grid-mixin'; import {transition} from '../core/core'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; /** * A concrete implementation of a general purpose bubble chart that allows data visualization using the @@ -74,7 +74,7 @@ export class BubbleChart extends BubbleMixin(CoordinateGridMixin) { .attr('class', this.BUBBLE_NODE_CLASS) .attr('transform', d => this._bubbleLocator(d)) .append('circle').attr('class', (d, i) => `${this.BUBBLE_CLASS} _${i}`) - .on('click', adaptHandler(d => this.onClick(d))) + .on('click', config._d3compat.eventHandler(d => this.onClick(d))) .classed('dc-tabbable', this._keyboardAccessible) .attr('fill', this.getColor) .attr('r', 0); diff --git a/src/charts/bubble-overlay.js b/src/charts/bubble-overlay.js index 721b64cbed..c1886e19b9 100644 --- a/src/charts/bubble-overlay.js +++ b/src/charts/bubble-overlay.js @@ -3,7 +3,7 @@ import {BubbleMixin} from '../base/bubble-mixin'; import {transition} from '../core/core'; import {constants} from '../core/constants'; import {utils} from '../core/utils'; -import {adaptHandler, d3compatPointer} from '../core/d3compat'; +import {config} from '../core/config'; const BUBBLE_OVERLAY_CLASS = 'bubble-overlay'; const BUBBLE_NODE_CLASS = 'node'; @@ -115,7 +115,7 @@ export class BubbleOverlay extends BubbleMixin(BaseMixin) { .classed('dc-tabbable', this._keyboardAccessible) .attr('r', 0) .attr('fill', this.getColor) - .on('click', adaptHandler(d => this.onClick(d))); + .on('click', config._d3compat.eventHandler(d => this.onClick(d))); } if (this._keyboardAccessible) { @@ -200,8 +200,8 @@ export class BubbleOverlay extends BubbleMixin(BaseMixin) { .append('rect') .attr('width', this.width()) .attr('height', this.height()) - .on('mousemove', adaptHandler((d, evt) => { - const position = d3compatPointer(evt, debugG.node()); + .on('mousemove', config._d3compat.eventHandler((d, evt) => { + const position = config._d3compat.pointer(evt, debugG.node()); const msg = `${position[0]}, ${position[1]}`; debugText.text(msg); })); diff --git a/src/charts/cbox-menu.js b/src/charts/cbox-menu.js index 6ccec3c5bf..099bf477bb 100644 --- a/src/charts/cbox-menu.js +++ b/src/charts/cbox-menu.js @@ -3,7 +3,7 @@ import {select} from 'd3-selection'; import {events} from '../core/events'; import {BaseMixin} from '../base/base-mixin'; import {utils} from '../core/utils' -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; const GROUP_CSS_CLASS = 'dc-cbox-group'; const ITEM_CSS_CLASS = 'dc-cbox-item'; @@ -121,7 +121,7 @@ export class CboxMenu extends BaseMixin { .append('input') .attr('type', 'reset') .text(this._promptText) - .on('click', adaptHandler(function (d, evt) { + .on('click', config._d3compat.eventHandler(function (d, evt) { return chart._onChange(d, evt, this); })); } else { @@ -141,7 +141,7 @@ export class CboxMenu extends BaseMixin { .selectAll(`li.${ITEM_CSS_CLASS}`) .sort(this._order); - this._cbox.on('change', adaptHandler(function (d, evt) { + this._cbox.on('change', config._d3compat.eventHandler(function (d, evt) { return chart._onChange(d, evt, this); })); return options; diff --git a/src/charts/data-grid.js b/src/charts/data-grid.js index ced2ac83f4..2dbb268eb1 100644 --- a/src/charts/data-grid.js +++ b/src/charts/data-grid.js @@ -2,7 +2,7 @@ import {ascending} from 'd3-array'; import {logger} from '../core/logger'; import {BaseMixin} from '../base/base-mixin'; -import {compatNestHelper} from '../core/d3compat'; +import {config} from '../core/config'; const LABEL_CSS_CLASS = 'dc-grid-label'; const ITEM_CSS_CLASS = 'dc-grid-item'; @@ -86,7 +86,7 @@ export class DataGrid extends BaseMixin { .sort((a, b) => this._order(this._sortBy(a), this._sortBy(b))) .slice(this._beginSlice, this._endSlice) - return compatNestHelper({ + return config._d3compat.nester({ key: this.section(), sortKeys: this._order, entries diff --git a/src/charts/data-table.js b/src/charts/data-table.js index a2688c7016..56d9053336 100644 --- a/src/charts/data-table.js +++ b/src/charts/data-table.js @@ -2,7 +2,7 @@ import {ascending} from 'd3-array'; import {logger} from '../core/logger'; import {BaseMixin} from '../base/base-mixin'; -import {compatNestHelper} from '../core/d3compat'; +import {config} from '../core/config'; const LABEL_CSS_CLASS = 'dc-table-label'; const ROW_CSS_CLASS = 'dc-table-row'; @@ -176,7 +176,7 @@ export class DataTable extends BaseMixin { entries = entries.sort((a, b) => this._order(this._sortBy(a), this._sortBy(b))).slice(this._beginSlice, this._endSlice) - return compatNestHelper({ + return config._d3compat.nester({ key: this.section(), sortKeys: this._order, entries diff --git a/src/charts/geo-choropleth-chart.js b/src/charts/geo-choropleth-chart.js index f794e6db55..65a7fd66f8 100644 --- a/src/charts/geo-choropleth-chart.js +++ b/src/charts/geo-choropleth-chart.js @@ -7,7 +7,7 @@ import {transition} from '../core/core'; import {logger} from '../core/logger'; import {events} from '../core/events'; import {utils} from '../core/utils'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; /** * The geo choropleth chart is designed as an easy way to create a crossfilter driven choropleth map @@ -149,7 +149,7 @@ export class GeoChoroplethChart extends ColorMixin(BaseMixin) { } return 'none'; }) - .on('click', adaptHandler(d => this.onClick(d, layerIndex))); + .on('click', config._d3compat.eventHandler(d => this.onClick(d, layerIndex))); if (this._keyboardAccessible) { this._makeKeyboardAccessible(this.onClick, layerIndex); diff --git a/src/charts/heatmap.js b/src/charts/heatmap.js index b998622cf1..83ee6e38f1 100644 --- a/src/charts/heatmap.js +++ b/src/charts/heatmap.js @@ -7,7 +7,7 @@ import {filters} from '../core/filters'; import {events} from '../core/events'; import {ColorMixin} from '../base/color-mixin'; import {MarginMixin} from '../base/margin-mixin'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; const DEFAULT_BORDER_RADIUS = 6.75; @@ -233,7 +233,7 @@ export class HeatMap extends ColorMixin(MarginMixin) { .attr('fill', 'white') .attr('x', (d, i) => cols(this.keyAccessor()(d, i))) .attr('y', (d, i) => rows(this.valueAccessor()(d, i))) - .on('click', adaptHandler(this.boxOnClick())); + .on('click', config._d3compat.eventHandler(this.boxOnClick())); if (this._keyboardAccessible) { this._makeKeyboardAccessible(this.boxOnClick); @@ -270,7 +270,7 @@ export class HeatMap extends ColorMixin(MarginMixin) { .style('text-anchor', 'middle') .attr('y', this.effectiveHeight()) .attr('dy', 12) - .on('click', adaptHandler(this.xAxisOnClick())) + .on('click', config._d3compat.eventHandler(this.xAxisOnClick())) .text(this.colsLabel()) .merge(gColsText); @@ -296,7 +296,7 @@ export class HeatMap extends ColorMixin(MarginMixin) { .attr('dx', -2) .attr('y', d => rows(d) + boxHeight / 2) .attr('dy', 6) - .on('click', adaptHandler(this.yAxisOnClick())) + .on('click', config._d3compat.eventHandler(this.yAxisOnClick())) .text(this.rowsLabel()) .merge(gRowsText); diff --git a/src/charts/html-legend.js b/src/charts/html-legend.js index f8e7a3f43a..de6c2c1287 100644 --- a/src/charts/html-legend.js +++ b/src/charts/html-legend.js @@ -1,8 +1,8 @@ import {select} from 'd3-selection'; -import {event} from 'd3-selection'; +//import {event} from 'd3-selection'; import {pluck, utils} from '../core/utils'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; import {constants} from '../core/constants'; /** @@ -55,9 +55,9 @@ export class HtmlLegend { .data(legendables).enter() .append('div') .classed(legendItemClassName, true) - .on('mouseover', adaptHandler(d => this._parent.legendHighlight(d))) - .on('mouseout', adaptHandler(d => this._parent.legendReset(d))) - .on('click', adaptHandler(d => this._parent.legendToggle(d))); + .on('mouseover', config._d3compat.eventHandler(d => this._parent.legendHighlight(d))) + .on('mouseout', config._d3compat.eventHandler(d => this._parent.legendReset(d))) + .on('click', config._d3compat.eventHandler(d => this._parent.legendToggle(d))); if (this._highlightSelected) { itemEnter.classed(constants.SELECTED_CLASS, d => filters.indexOf(d.name) !== -1); diff --git a/src/charts/legend.js b/src/charts/legend.js index a7673e9b7a..6def2b93fe 100644 --- a/src/charts/legend.js +++ b/src/charts/legend.js @@ -1,5 +1,5 @@ import {pluck, utils} from '../core/utils'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; import {constants} from '../core/constants'; const LABEL_GAP = 2; @@ -241,7 +241,7 @@ export class Legend { .attr('tabindex', 0); tabElements - .on('keydown', adaptHandler((d, event) => { + .on('keydown', config._d3compat.eventHandler((d, event) => { // trigger only if d is an object if (event.keyCode === 13 && typeof d === 'object') { d.chart.legendToggle(d) @@ -252,10 +252,10 @@ export class Legend { event.preventDefault(); } })) - .on('focus', adaptHandler(d => { + .on('focus', config._d3compat.eventHandler(d => { this._parent.legendHighlight(d); })) - .on('blur', adaptHandler(d => { + .on('blur', config._d3compat.eventHandler(d => { this._parent.legendReset(d); })); } @@ -277,13 +277,13 @@ export class Legend { .enter() .append('g') .attr('class', 'dc-legend-item') - .on('mouseover', adaptHandler(d => { + .on('mouseover', config._d3compat.eventHandler(d => { this._parent.legendHighlight(d); })) - .on('mouseout', adaptHandler(d => { + .on('mouseout', config._d3compat.eventHandler(d => { this._parent.legendReset(d); })) - .on('click', adaptHandler(d => { + .on('click', config._d3compat.eventHandler(d => { d.chart.legendToggle(d); })); diff --git a/src/charts/pie-chart.js b/src/charts/pie-chart.js index cec7c3606f..50f35279e4 100644 --- a/src/charts/pie-chart.js +++ b/src/charts/pie-chart.js @@ -7,7 +7,7 @@ import {CapMixin} from '../base/cap-mixin'; import {ColorMixin} from '../base/color-mixin'; import {BaseMixin} from '../base/base-mixin'; import {transition} from '../core/core'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; const DEFAULT_MIN_ANGLE_FOR_LABEL = 0.5; @@ -162,7 +162,7 @@ export class PieChart extends CapMixin(ColorMixin(BaseMixin)) { _createSlicePath (slicesEnter, arcs) { const slicePath = slicesEnter.append('path') .attr('fill', (d, i) => this._fill(d, i)) - .on('click', adaptHandler(d => this._onClick(d))) + .on('click', config._d3compat.eventHandler(d => this._onClick(d))) .attr('d', (d, i) => this._safeArc(d, i, arcs)); if (this._keyboardAccessible) { @@ -219,11 +219,11 @@ export class PieChart extends CapMixin(ColorMixin(BaseMixin)) { } return classes; }) - .on('click', adaptHandler(d => this._onClick(d))) - .on('mouseover', adaptHandler(d => { + .on('click', config._d3compat.eventHandler(d => this._onClick(d))) + .on('mouseover', config._d3compat.eventHandler(d => { this._highlightSlice(d.index, true); })) - .on('mouseout', adaptHandler(d => { + .on('mouseout', config._d3compat.eventHandler(d => { this._highlightSlice(d.index, false); })); this._positionLabels(labelsEnter, arcs); @@ -243,11 +243,11 @@ export class PieChart extends CapMixin(ColorMixin(BaseMixin)) { .enter() .append('polyline') .attr('class', (d, i) => `pie-path _${i} ${this._sliceCssClass}`) - .on('click', adaptHandler(d => this._onClick(d))) - .on('mouseover', adaptHandler(d => { + .on('click', config._d3compat.eventHandler(d => this._onClick(d))) + .on('mouseover', config._d3compat.eventHandler(d => { this._highlightSlice(d.index, true); })) - .on('mouseout', adaptHandler(d => { + .on('mouseout', config._d3compat.eventHandler(d => { this._highlightSlice(d.index, false); })) .merge(polyline); diff --git a/src/charts/row-chart.js b/src/charts/row-chart.js index fabedf6ea1..4cc69f07e3 100644 --- a/src/charts/row-chart.js +++ b/src/charts/row-chart.js @@ -6,7 +6,7 @@ import {CapMixin} from '../base/cap-mixin'; import {MarginMixin} from '../base/margin-mixin'; import {ColorMixin} from '../base/color-mixin'; import {transition} from '../core/core'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; /** * Concrete row chart implementation. @@ -191,13 +191,13 @@ export class RowChart extends CapMixin(ColorMixin(MarginMixin)) { const rect = rows.attr('transform', (d, i) => `translate(0,${(i + 1) * this._gap + i * height})`).select('rect') .attr('height', height) .attr('fill', this.getColor) - .on('click', adaptHandler(d => this._onClick(d))) + .on('click', config._d3compat.eventHandler(d => this._onClick(d))) .classed('dc-tabbable', this._keyboardAccessible) .classed('deselected', d => (this.hasFilter()) ? !this._isSelectedRow(d) : false) .classed('selected', d => (this.hasFilter()) ? this._isSelectedRow(d) : false); if (this._keyboardAccessible) { - this._makeKeyboardAccessible(adaptHandler(d => this._onClick(d))); + this._makeKeyboardAccessible(config._d3compat.eventHandler(d => this._onClick(d))); } transition(rect, this.transitionDuration(), this.transitionDelay()) @@ -218,12 +218,12 @@ export class RowChart extends CapMixin(ColorMixin(MarginMixin)) { _createLabels (rowEnter) { if (this.renderLabel()) { rowEnter.append('text') - .on('click', adaptHandler(d => this._onClick(d))); + .on('click', config._d3compat.eventHandler(d => this._onClick(d))); } if (this.renderTitleLabel()) { rowEnter.append('text') .attr('class', this._titleRowCssClass) - .on('click', adaptHandler(d => this._onClick(d))); + .on('click', config._d3compat.eventHandler(d => this._onClick(d))); } } @@ -233,7 +233,7 @@ export class RowChart extends CapMixin(ColorMixin(MarginMixin)) { .attr('x', this._labelOffsetX) .attr('y', this._labelOffsetY) .attr('dy', this._dyOffset) - .on('click', adaptHandler(d => this._onClick(d))) + .on('click', config._d3compat.eventHandler(d => this._onClick(d))) .attr('class', (d, i) => `${this._rowCssClass} _${i}`) .text(d => this.label()(d)); transition(lab, this.transitionDuration(), this.transitionDelay()) @@ -245,7 +245,7 @@ export class RowChart extends CapMixin(ColorMixin(MarginMixin)) { .attr('y', this._labelOffsetY) .attr('dy', this._dyOffset) .attr('text-anchor', 'end') - .on('click', adaptHandler(d => this._onClick(d))) + .on('click', config._d3compat.eventHandler(d => this._onClick(d))) .attr('class', (d, i) => `${this._titleRowCssClass} _${i}`) .text(d => this.title()(d)); transition(titlelab, this.transitionDuration(), this.transitionDelay()) diff --git a/src/charts/select-menu.js b/src/charts/select-menu.js index d3cf05074c..cb41c917f1 100644 --- a/src/charts/select-menu.js +++ b/src/charts/select-menu.js @@ -1,7 +1,7 @@ import {events} from '../core/events'; import {BaseMixin} from '../base/base-mixin'; import {logger} from '../core/logger'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; const SELECT_CSS_CLASS = 'dc-select-menu'; const OPTION_CSS_CLASS = 'dc-select-option'; @@ -96,7 +96,7 @@ export class SelectMenu extends BaseMixin { this._select.selectAll(`option.${OPTION_CSS_CLASS}`).sort(this._order); - this._select.on('change', adaptHandler((d, evt) => this._onChange(d, evt))); + this._select.on('change', config._d3compat.eventHandler((d, evt) => this._onChange(d, evt))); } _onChange (_d, evt) { diff --git a/src/charts/series-chart.js b/src/charts/series-chart.js index 2ec99466a5..a0c9696295 100644 --- a/src/charts/series-chart.js +++ b/src/charts/series-chart.js @@ -3,7 +3,7 @@ import {ascending} from 'd3-array'; import {CompositeChart} from './composite-chart'; import {lineChart} from './line-chart'; import {utils} from '../core/utils'; -import {compatNestHelper} from '../core/d3compat'; +import {config} from '../core/config'; /** * A series chart is a chart that shows multiple series of data overlaid on one chart, where the @@ -56,7 +56,7 @@ export class SeriesChart extends CompositeChart { const keep = []; let childrenChanged; - const nesting = compatNestHelper({ + const nesting = config._d3compat.nester({ key: this._seriesAccessor, sortKeys: this._seriesSort, sortValues: this._valueSort, diff --git a/src/charts/sunburst-chart.js b/src/charts/sunburst-chart.js index d8fc8f9080..5f19b51173 100644 --- a/src/charts/sunburst-chart.js +++ b/src/charts/sunburst-chart.js @@ -7,7 +7,7 @@ import {interpolate} from 'd3-interpolate'; import {transition} from '../core/core'; import {filters} from '../core/filters'; import {utils, pluck} from '../core/utils'; -import {adaptHandler} from '../core/d3compat'; +import {config} from '../core/config'; import {events} from '../core/events'; import {ColorMixin} from '../base/color-mixin'; import {BaseMixin} from '../base/base-mixin'; @@ -172,7 +172,7 @@ export class SunburstChart extends ColorMixin(BaseMixin) { _createSlicePath (slicesEnter, arcs) { const slicePath = slicesEnter.append('path') .attr('fill', (d, i) => this._fill(d, i)) - .on('click', adaptHandler(d => this.onClick(d))) + .on('click', config._d3compat.eventHandler(d => this.onClick(d))) .classed('dc-tabbable', this._keyboardAccessible) .attr('d', d => this._safeArc(arcs, d)); @@ -225,7 +225,7 @@ export class SunburstChart extends ColorMixin(BaseMixin) { } return classes; }) - .on('click', adaptHandler(d => this.onClick(d))); + .on('click', config._d3compat.eventHandler(d => this.onClick(d))); this._positionLabels(labelsEnter, arcs); } } diff --git a/src/core/config.js b/src/core/config.js index e2c093a3d5..8a2ba9af7d 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -18,6 +18,17 @@ export class Config { this._renderlet = null; + this._d3compat = { + eventHandler: handler => function eventHandler (a, b) { + console.warn('No d3.js compatbility event handler registered, defaulting to v6 behavior.'); + handler.call(this, b, a); + }, + nester: ({key, sortKeys, sortValues, entries}) => { + throw new Error('No d3.js compatbility nester registered, load v5 or v6 compability layer.'); + }, + pointer: () => { throw new Error('No d3.js compatbility pointer registered, load v5 or v6 compability layer.'); } + }; + /** * If this boolean is set truthy, all transitions will be disabled, and changes to the charts will happen * immediately. diff --git a/src/core/d3compat-v5.js b/src/core/d3compat-v5.js new file mode 100644 index 0000000000..7cf8b02e9b --- /dev/null +++ b/src/core/d3compat-v5.js @@ -0,0 +1,27 @@ +import { version } from 'd3'; + +import { event, mouse } from 'd3-selection'; +import { nest } from 'd3-collection'; + +import { config } from './config'; + +const majorVer = +version[0]; + +if (majorVer < 6) { + Object.assign(config._d3compat, { + eventHandler: handler => function eventHandler (a ,b) { + handler.call(this, a, event); + }, + nester: ({key, sortKeys, sortValues, entries}) => { + const nester = nest().key(key); + if (sortKeys) { + nester.sortKeys(sortKeys); + } + if (sortValues) { + nester.sortValues(sortValues); + } + return nester.entries(entries); + }, + pointer: (evt, elem) => mouse(elem) + }); +} \ No newline at end of file diff --git a/src/core/d3compat-v6.js b/src/core/d3compat-v6.js new file mode 100644 index 0000000000..4c7cc0da86 --- /dev/null +++ b/src/core/d3compat-v6.js @@ -0,0 +1,32 @@ +import { version } from 'd3'; + +import { pointer } from 'd3-selection'; +import { groups } from 'd3-array'; + +import { config } from './config'; + +const majorVer = +version[0]; + +if (majorVer > 5) { + Object.assign(config._d3compat, { + eventHandler: handler => function eventHandler (a, b) { + handler.call(this, b, a); + }, + nester: ({key, sortKeys, sortValues, entries}) => { + if (sortValues) { + entries = [...entries].sort(sortValues); + } + let out = groups(entries, key); + if (sortKeys) { + out = out.sort(sortKeys); + } + + // remap to d3@v5 structure + return out.map(e => ({ + key: `${e[0]}`, // d3@v5 always returns key as string + values: e[1] + })); + }, + pointer + }); +} \ No newline at end of file diff --git a/src/core/d3compat.js b/src/core/d3compat.js deleted file mode 100644 index b42048728e..0000000000 --- a/src/core/d3compat.js +++ /dev/null @@ -1,61 +0,0 @@ -import {event, mouse, pointer} from 'd3-selection'; -import {nest} from 'd3-collection'; -import {groups} from 'd3-array'; - -// d3v6 has removed `d3.mouse` in favor of `d3.pointer` -export const d3compatPointer = - typeof pointer === 'function' ? (evt, elem) => pointer(evt, elem) : (evt, elem) => mouse(elem); - -// d3v6 has changed the arguments for event handlers. -// We are creating a wrapper which detects if the first argument is an event, which indicated d3@v6 -// Otherwise we assume lower versions of d3. -// The underlying handler will always receive bound datum as the first argument and the event as the second argument. -// It is possible that any of these can actually be undefined (or null). -export function adaptHandler (handler) { - return function (a, b) { - if (a && a.target) { - // d3@v6 - b is __data__, a is the event - handler.call(this, b, a); - } else { - // older d3 - a is __data__, event from global d3.event - handler.call(this, a, event); - } - } -} - -function _d3v5Nester ({key, sortKeys, sortValues, entries}) { - const nester = nest().key(key); - if (sortKeys) { - nester.sortKeys(sortKeys); - } - if (sortValues) { - nester.sortValues(sortValues); - } - return nester.entries(entries); -} - -function _d3v6Nester ({key, sortKeys, sortValues, entries}) { - if (sortValues) { - entries = [...entries].sort(sortValues); - } - let out = groups(entries, key); - if (sortKeys) { - out = out.sort(sortKeys); - } - - // remap to d3@v5 structure - return out.map(e => ({ - key: `${e[0]}`, // d3@v5 always returns key as string - values: e[1] - })); -} - -export function compatNestHelper ({key, sortKeys, sortValues, entries}) { - if (groups) { - // d3@v6 - return _d3v6Nester({key, sortKeys, sortValues, entries}); - } else { - // older d3 - return _d3v5Nester({key, sortKeys, sortValues, entries}); - } -} diff --git a/src/index-with-version.js b/src/index-with-version.js index 2eef4279bf..d115ea81ae 100644 --- a/src/index-with-version.js +++ b/src/index-with-version.js @@ -2,3 +2,5 @@ export {version} from '../package.json'; export * from './index'; +import './core/d3compat-v5.js'; +import './core/d3compat-v6.js'; \ No newline at end of file diff --git a/src/index.js b/src/index.js index a8ba8d6d17..17e45f5c65 100644 --- a/src/index.js +++ b/src/index.js @@ -10,7 +10,6 @@ export * from './core/logger'; export * from './core/printers'; export * from './core/units'; export * from './core/utils'; -export * from './core/d3compat'; export * from './base/base-mixin'; export * from './base/bubble-mixin'; diff --git a/web-src/examples/filter-stacks.html b/web-src/examples/filter-stacks.html index 50e5d1534e..3d05134840 100644 --- a/web-src/examples/filter-stacks.html +++ b/web-src/examples/filter-stacks.html @@ -121,7 +121,7 @@ var key = multikey(d.x, d.layer); return chart.filter() && chart.filters().indexOf(key)===-1; }) - .on('click', dc.adaptHandler(function(d) { + .on('click', dc.config._d3compat.eventHandler(function(d) { chart.filter(multikey(d.x, d.layer)); dc.redrawAll(); })); From add89b1c23129286d839515aaba80ff7e9662973 Mon Sep 17 00:00:00 2001 From: Patrik Kullman Date: Mon, 5 Apr 2021 00:04:51 +0200 Subject: [PATCH 2/7] fix: eventHandler Misleading comments/docs, both eventHandler versions are used in d3@v6 --- src/core/d3compat-v5.js | 8 +++++++- src/core/d3compat-v6.js | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/core/d3compat-v5.js b/src/core/d3compat-v5.js index 7cf8b02e9b..a0dc7f22be 100644 --- a/src/core/d3compat-v5.js +++ b/src/core/d3compat-v5.js @@ -10,7 +10,13 @@ const majorVer = +version[0]; if (majorVer < 6) { Object.assign(config._d3compat, { eventHandler: handler => function eventHandler (a ,b) { - handler.call(this, a, event); + if (a && a.target) { + // d3@v6 - b is __data__, a is the event + handler.call(this, b, a); + } else { + // older d3 - a is __data__, event from global d3.event + handler.call(this, a, event); + } }, nester: ({key, sortKeys, sortValues, entries}) => { const nester = nest().key(key); diff --git a/src/core/d3compat-v6.js b/src/core/d3compat-v6.js index 4c7cc0da86..cdd5cb73a3 100644 --- a/src/core/d3compat-v6.js +++ b/src/core/d3compat-v6.js @@ -9,8 +9,14 @@ const majorVer = +version[0]; if (majorVer > 5) { Object.assign(config._d3compat, { - eventHandler: handler => function eventHandler (a, b) { - handler.call(this, b, a); + eventHandler: handler => function (a, b) { + if (a && a.target) { + // d3@v6 - b is __data__, a is the event + handler.call(this, b, a); + } else { + // older d3 - a is __data__, event from global d3.event + handler.call(this, a); + } }, nester: ({key, sortKeys, sortValues, entries}) => { if (sortValues) { From a8af5dec51c1c7f74eea762ae6a15292353f857b Mon Sep 17 00:00:00 2001 From: Patrik Kullman Date: Tue, 6 Apr 2021 16:47:50 +0200 Subject: [PATCH 3/7] fix: avoid rollup d3 dep warnings --- rollup.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/rollup.config.js b/rollup.config.js index 5e5b6c312a..ebe31227f6 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -13,6 +13,7 @@ const licensePlugin = license({ }); const d3Modules = { + 'd3': 'd3', 'd3-array': 'd3', 'd3-axis': 'd3', 'd3-brush': 'd3', From 33fabad71ae19f2b548b0ece643d20ec7a7b7ebc Mon Sep 17 00:00:00 2001 From: Patrik Kullman Date: Tue, 6 Apr 2021 17:27:49 +0200 Subject: [PATCH 4/7] fix: html-legend: use legend keydown logic --- src/charts/html-legend.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/charts/html-legend.js b/src/charts/html-legend.js index de6c2c1287..8d7d879f60 100644 --- a/src/charts/html-legend.js +++ b/src/charts/html-legend.js @@ -1,5 +1,4 @@ import {select} from 'd3-selection'; -//import {event} from 'd3-selection'; import {pluck, utils} from '../core/utils'; import {config} from '../core/config'; @@ -209,7 +208,7 @@ export class HtmlLegend { .attr('tabindex', 0); tabElements - .on('keydown', d => { + .on('keydown', config._d3compat.eventHandler((d, event) => { // trigger only if d is an object if (event.keyCode === 13 && typeof d === 'object') { d.chart.legendToggle(d) @@ -219,7 +218,7 @@ export class HtmlLegend { d.chart.legendToggle(d) event.preventDefault(); } - }) + })) .on('focus', d => { this._parent.legendHighlight(d); }) From a42bf5c0eaaf9d87ff55a70110e4bbbcfdfeea41 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Tue, 6 Apr 2021 21:33:26 +0530 Subject: [PATCH 5/7] Make event handler dc@5 and dc@6 compatible --- src/charts/html-legend.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/charts/html-legend.js b/src/charts/html-legend.js index 8d7d879f60..8fcc85432f 100644 --- a/src/charts/html-legend.js +++ b/src/charts/html-legend.js @@ -219,12 +219,12 @@ export class HtmlLegend { event.preventDefault(); } })) - .on('focus', d => { + .on('focus', config._d3compat.eventHandler(d => { this._parent.legendHighlight(d); - }) - .on('blur', d => { + })) + .on('blur', config._d3compat.eventHandler(d => { this._parent.legendReset(d); - }); + })); } } From 924aec0e697e3e758e33239b10052f7020d8f3db Mon Sep 17 00:00:00 2001 From: Patrik Kullman Date: Tue, 6 Apr 2021 21:11:36 +0200 Subject: [PATCH 6/7] fix: move compat layer out from config --- src/base/base-mixin.js | 4 ++-- src/base/bubble-mixin.js | 4 ++-- src/base/coordinate-grid-mixin.js | 6 +++--- src/charts/bar-chart.js | 6 +++--- src/charts/box-plot.js | 4 ++-- src/charts/bubble-chart.js | 4 ++-- src/charts/bubble-overlay.js | 8 ++++---- src/charts/cbox-menu.js | 6 +++--- src/charts/data-grid.js | 4 ++-- src/charts/data-table.js | 4 ++-- src/charts/geo-choropleth-chart.js | 4 ++-- src/charts/heatmap.js | 8 ++++---- src/charts/html-legend.js | 14 +++++++------- src/charts/legend.js | 14 +++++++------- src/charts/pie-chart.js | 16 ++++++++-------- src/charts/row-chart.js | 14 +++++++------- src/charts/select-menu.js | 4 ++-- src/charts/series-chart.js | 4 ++-- src/charts/sunburst-chart.js | 6 +++--- src/{core/d3compat-v5.js => compat/d3v5.js} | 4 ++-- src/{core/d3compat-v6.js => compat/d3v6.js} | 4 ++-- src/core/config.js | 5 +++++ src/index-with-version.js | 4 ++-- web-src/examples/filter-stacks.html | 2 +- 24 files changed, 79 insertions(+), 74 deletions(-) rename src/{core/d3compat-v5.js => compat/d3v5.js} (92%) rename src/{core/d3compat-v6.js => compat/d3v6.js} (93%) diff --git a/src/base/base-mixin.js b/src/base/base-mixin.js index dd73d8f7d4..95262d26f8 100644 --- a/src/base/base-mixin.js +++ b/src/base/base-mixin.js @@ -11,7 +11,7 @@ import {logger} from '../core/logger'; import {printers} from '../core/printers'; import {InvalidStateException} from '../core/invalid-state-exception'; import {BadArgumentException} from '../core/bad-argument-exception'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const _defaultFilterHandler = (dimension, filters) => { if (filters.length === 0) { @@ -723,7 +723,7 @@ export class BaseMixin { .attr('tabindex', 0); if (onClickFunction) { - tabElements.on('keydown', config._d3compat.eventHandler((d, event) => { + tabElements.on('keydown', d3compat.eventHandler((d, event) => { // trigger only if d is an object undestood by KeyAccessor() if (event.keyCode === 13 && typeof d === 'object') { onClickFunction.call(this, d, ...onClickArgs) diff --git a/src/base/bubble-mixin.js b/src/base/bubble-mixin.js index 6a03cacfbf..d1d688bc73 100644 --- a/src/base/bubble-mixin.js +++ b/src/base/bubble-mixin.js @@ -4,7 +4,7 @@ import { scaleLinear } from 'd3-scale'; import {ColorMixin} from './color-mixin'; import {transition} from '../core/core'; import {events} from '../core/events'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; /** * This Mixin provides reusable functionalities for any chart that needs to visualize data using bubbles. @@ -156,7 +156,7 @@ export const BubbleMixin = Base => class extends ColorMixin(Base) { label = bubbleGEnter.append('text') .attr('text-anchor', 'middle') .attr('dy', '.3em') - .on('click', config._d3compat.eventHandler(d => this.onClick(d))); + .on('click', d3compat.eventHandler(d => this.onClick(d))); } label diff --git a/src/base/coordinate-grid-mixin.js b/src/base/coordinate-grid-mixin.js index c8d6c459ca..1669d1621e 100644 --- a/src/base/coordinate-grid-mixin.js +++ b/src/base/coordinate-grid-mixin.js @@ -12,7 +12,7 @@ import {optionalTransition, transition} from '../core/core'; import {units} from '../core/units'; import {constants} from '../core/constants'; import {utils} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; import {logger} from '../core/logger'; import {filters} from '../core/filters'; import {events} from '../core/events'; @@ -78,7 +78,7 @@ export class CoordinateGridMixin extends ColorMixin(MarginMixin) { this._zoomScale = [1, Infinity]; this._zoomOutRestrict = true; - this._zoom = zoom().on('zoom', config._d3compat.eventHandler((d, evt) => this._onZoom(evt))); + this._zoom = zoom().on('zoom', d3compat.eventHandler((d, evt) => this._onZoom(evt))); this._nullZoom = zoom().on('zoom', null); this._hasBeenMouseZoomable = false; this._ignoreZoomEvents = false; // ignore when carrying out programmatic zoom operations @@ -969,7 +969,7 @@ export class CoordinateGridMixin extends ColorMixin(MarginMixin) { renderBrush (g, doTransition) { if (this._brushOn) { - this._brush.on('start brush end', config._d3compat.eventHandler((d, evt) => this._brushing(evt))); + this._brush.on('start brush end', d3compat.eventHandler((d, evt) => this._brushing(evt))); // To retrieve selection we need self._gBrush this._gBrush = g.append('g') diff --git a/src/charts/bar-chart.js b/src/charts/bar-chart.js index fb9d014243..b39f709ed3 100644 --- a/src/charts/bar-chart.js +++ b/src/charts/bar-chart.js @@ -5,7 +5,7 @@ import {transition} from '../core/core'; import {constants} from '../core/constants'; import {logger} from '../core/logger'; import {pluck, utils} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const MIN_BAR_WIDTH = 1; const DEFAULT_GAP_BETWEEN_BARS = 2; @@ -145,7 +145,7 @@ export class BarChart extends StackMixin { .merge(labels); if (this.isOrdinal()) { - labelsEnterUpdate.on('click', config._d3compat.eventHandler(d => this.onClick(d))); + labelsEnterUpdate.on('click', d3compat.eventHandler(d => this.onClick(d))); labelsEnterUpdate.attr('cursor', 'pointer'); } @@ -190,7 +190,7 @@ export class BarChart extends StackMixin { } if (this.isOrdinal()) { - barsEnterUpdate.on('click', config._d3compat.eventHandler(d => this.onClick(d))); + barsEnterUpdate.on('click', d3compat.eventHandler(d => this.onClick(d))); } if (this._keyboardAccessible) { diff --git a/src/charts/box-plot.js b/src/charts/box-plot.js index 1620461f1c..8d737c454d 100644 --- a/src/charts/box-plot.js +++ b/src/charts/box-plot.js @@ -7,7 +7,7 @@ import {CoordinateGridMixin} from '../base/coordinate-grid-mixin'; import {transition} from '../core/core'; import {units} from '../core/units'; import {utils} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; // Returns a function to compute the interquartile range. function defaultWhiskersIQR (k) { @@ -198,7 +198,7 @@ export class BoxPlot extends CoordinateGridMixin { .classed('dc-tabbable', this._keyboardAccessible) .attr('transform', (d, i) => this._boxTransform(d, i)) .call(this._box) - .on('click', config._d3compat.eventHandler(d => { + .on('click', d3compat.eventHandler(d => { this.filter(this.keyAccessor()(d)); this.redrawGroup(); })) diff --git a/src/charts/bubble-chart.js b/src/charts/bubble-chart.js index 1fa9135d14..1816d60d24 100644 --- a/src/charts/bubble-chart.js +++ b/src/charts/bubble-chart.js @@ -1,7 +1,7 @@ import {BubbleMixin} from '../base/bubble-mixin'; import {CoordinateGridMixin} from '../base/coordinate-grid-mixin'; import {transition} from '../core/core'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; /** * A concrete implementation of a general purpose bubble chart that allows data visualization using the @@ -74,7 +74,7 @@ export class BubbleChart extends BubbleMixin(CoordinateGridMixin) { .attr('class', this.BUBBLE_NODE_CLASS) .attr('transform', d => this._bubbleLocator(d)) .append('circle').attr('class', (d, i) => `${this.BUBBLE_CLASS} _${i}`) - .on('click', config._d3compat.eventHandler(d => this.onClick(d))) + .on('click', d3compat.eventHandler(d => this.onClick(d))) .classed('dc-tabbable', this._keyboardAccessible) .attr('fill', this.getColor) .attr('r', 0); diff --git a/src/charts/bubble-overlay.js b/src/charts/bubble-overlay.js index c1886e19b9..3f74c075aa 100644 --- a/src/charts/bubble-overlay.js +++ b/src/charts/bubble-overlay.js @@ -3,7 +3,7 @@ import {BubbleMixin} from '../base/bubble-mixin'; import {transition} from '../core/core'; import {constants} from '../core/constants'; import {utils} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const BUBBLE_OVERLAY_CLASS = 'bubble-overlay'; const BUBBLE_NODE_CLASS = 'node'; @@ -115,7 +115,7 @@ export class BubbleOverlay extends BubbleMixin(BaseMixin) { .classed('dc-tabbable', this._keyboardAccessible) .attr('r', 0) .attr('fill', this.getColor) - .on('click', config._d3compat.eventHandler(d => this.onClick(d))); + .on('click', d3compat.eventHandler(d => this.onClick(d))); } if (this._keyboardAccessible) { @@ -200,8 +200,8 @@ export class BubbleOverlay extends BubbleMixin(BaseMixin) { .append('rect') .attr('width', this.width()) .attr('height', this.height()) - .on('mousemove', config._d3compat.eventHandler((d, evt) => { - const position = config._d3compat.pointer(evt, debugG.node()); + .on('mousemove', d3compat.eventHandler((d, evt) => { + const position = d3compat.pointer(evt, debugG.node()); const msg = `${position[0]}, ${position[1]}`; debugText.text(msg); })); diff --git a/src/charts/cbox-menu.js b/src/charts/cbox-menu.js index 099bf477bb..e49f75c183 100644 --- a/src/charts/cbox-menu.js +++ b/src/charts/cbox-menu.js @@ -3,7 +3,7 @@ import {select} from 'd3-selection'; import {events} from '../core/events'; import {BaseMixin} from '../base/base-mixin'; import {utils} from '../core/utils' -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const GROUP_CSS_CLASS = 'dc-cbox-group'; const ITEM_CSS_CLASS = 'dc-cbox-item'; @@ -121,7 +121,7 @@ export class CboxMenu extends BaseMixin { .append('input') .attr('type', 'reset') .text(this._promptText) - .on('click', config._d3compat.eventHandler(function (d, evt) { + .on('click', d3compat.eventHandler(function (d, evt) { return chart._onChange(d, evt, this); })); } else { @@ -141,7 +141,7 @@ export class CboxMenu extends BaseMixin { .selectAll(`li.${ITEM_CSS_CLASS}`) .sort(this._order); - this._cbox.on('change', config._d3compat.eventHandler(function (d, evt) { + this._cbox.on('change', d3compat.eventHandler(function (d, evt) { return chart._onChange(d, evt, this); })); return options; diff --git a/src/charts/data-grid.js b/src/charts/data-grid.js index 2dbb268eb1..b7a9d3123a 100644 --- a/src/charts/data-grid.js +++ b/src/charts/data-grid.js @@ -2,7 +2,7 @@ import {ascending} from 'd3-array'; import {logger} from '../core/logger'; import {BaseMixin} from '../base/base-mixin'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const LABEL_CSS_CLASS = 'dc-grid-label'; const ITEM_CSS_CLASS = 'dc-grid-item'; @@ -86,7 +86,7 @@ export class DataGrid extends BaseMixin { .sort((a, b) => this._order(this._sortBy(a), this._sortBy(b))) .slice(this._beginSlice, this._endSlice) - return config._d3compat.nester({ + return d3compat.nester({ key: this.section(), sortKeys: this._order, entries diff --git a/src/charts/data-table.js b/src/charts/data-table.js index 56d9053336..b1511105cf 100644 --- a/src/charts/data-table.js +++ b/src/charts/data-table.js @@ -2,7 +2,7 @@ import {ascending} from 'd3-array'; import {logger} from '../core/logger'; import {BaseMixin} from '../base/base-mixin'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const LABEL_CSS_CLASS = 'dc-table-label'; const ROW_CSS_CLASS = 'dc-table-row'; @@ -176,7 +176,7 @@ export class DataTable extends BaseMixin { entries = entries.sort((a, b) => this._order(this._sortBy(a), this._sortBy(b))).slice(this._beginSlice, this._endSlice) - return config._d3compat.nester({ + return d3compat.nester({ key: this.section(), sortKeys: this._order, entries diff --git a/src/charts/geo-choropleth-chart.js b/src/charts/geo-choropleth-chart.js index 65a7fd66f8..21bd26c46a 100644 --- a/src/charts/geo-choropleth-chart.js +++ b/src/charts/geo-choropleth-chart.js @@ -7,7 +7,7 @@ import {transition} from '../core/core'; import {logger} from '../core/logger'; import {events} from '../core/events'; import {utils} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; /** * The geo choropleth chart is designed as an easy way to create a crossfilter driven choropleth map @@ -149,7 +149,7 @@ export class GeoChoroplethChart extends ColorMixin(BaseMixin) { } return 'none'; }) - .on('click', config._d3compat.eventHandler(d => this.onClick(d, layerIndex))); + .on('click', d3compat.eventHandler(d => this.onClick(d, layerIndex))); if (this._keyboardAccessible) { this._makeKeyboardAccessible(this.onClick, layerIndex); diff --git a/src/charts/heatmap.js b/src/charts/heatmap.js index 83ee6e38f1..8149d741df 100644 --- a/src/charts/heatmap.js +++ b/src/charts/heatmap.js @@ -7,7 +7,7 @@ import {filters} from '../core/filters'; import {events} from '../core/events'; import {ColorMixin} from '../base/color-mixin'; import {MarginMixin} from '../base/margin-mixin'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const DEFAULT_BORDER_RADIUS = 6.75; @@ -233,7 +233,7 @@ export class HeatMap extends ColorMixin(MarginMixin) { .attr('fill', 'white') .attr('x', (d, i) => cols(this.keyAccessor()(d, i))) .attr('y', (d, i) => rows(this.valueAccessor()(d, i))) - .on('click', config._d3compat.eventHandler(this.boxOnClick())); + .on('click', d3compat.eventHandler(this.boxOnClick())); if (this._keyboardAccessible) { this._makeKeyboardAccessible(this.boxOnClick); @@ -270,7 +270,7 @@ export class HeatMap extends ColorMixin(MarginMixin) { .style('text-anchor', 'middle') .attr('y', this.effectiveHeight()) .attr('dy', 12) - .on('click', config._d3compat.eventHandler(this.xAxisOnClick())) + .on('click', d3compat.eventHandler(this.xAxisOnClick())) .text(this.colsLabel()) .merge(gColsText); @@ -296,7 +296,7 @@ export class HeatMap extends ColorMixin(MarginMixin) { .attr('dx', -2) .attr('y', d => rows(d) + boxHeight / 2) .attr('dy', 6) - .on('click', config._d3compat.eventHandler(this.yAxisOnClick())) + .on('click', d3compat.eventHandler(this.yAxisOnClick())) .text(this.rowsLabel()) .merge(gRowsText); diff --git a/src/charts/html-legend.js b/src/charts/html-legend.js index 8fcc85432f..bb0fcdf411 100644 --- a/src/charts/html-legend.js +++ b/src/charts/html-legend.js @@ -1,7 +1,7 @@ import {select} from 'd3-selection'; import {pluck, utils} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; import {constants} from '../core/constants'; /** @@ -54,9 +54,9 @@ export class HtmlLegend { .data(legendables).enter() .append('div') .classed(legendItemClassName, true) - .on('mouseover', config._d3compat.eventHandler(d => this._parent.legendHighlight(d))) - .on('mouseout', config._d3compat.eventHandler(d => this._parent.legendReset(d))) - .on('click', config._d3compat.eventHandler(d => this._parent.legendToggle(d))); + .on('mouseover', d3compat.eventHandler(d => this._parent.legendHighlight(d))) + .on('mouseout', d3compat.eventHandler(d => this._parent.legendReset(d))) + .on('click', d3compat.eventHandler(d => this._parent.legendToggle(d))); if (this._highlightSelected) { itemEnter.classed(constants.SELECTED_CLASS, d => filters.indexOf(d.name) !== -1); @@ -208,7 +208,7 @@ export class HtmlLegend { .attr('tabindex', 0); tabElements - .on('keydown', config._d3compat.eventHandler((d, event) => { + .on('keydown', d3compat.eventHandler((d, event) => { // trigger only if d is an object if (event.keyCode === 13 && typeof d === 'object') { d.chart.legendToggle(d) @@ -219,10 +219,10 @@ export class HtmlLegend { event.preventDefault(); } })) - .on('focus', config._d3compat.eventHandler(d => { + .on('focus', d3compat.eventHandler(d => { this._parent.legendHighlight(d); })) - .on('blur', config._d3compat.eventHandler(d => { + .on('blur', d3compat.eventHandler(d => { this._parent.legendReset(d); })); } diff --git a/src/charts/legend.js b/src/charts/legend.js index 6def2b93fe..aaed977ffd 100644 --- a/src/charts/legend.js +++ b/src/charts/legend.js @@ -1,5 +1,5 @@ import {pluck, utils} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; import {constants} from '../core/constants'; const LABEL_GAP = 2; @@ -241,7 +241,7 @@ export class Legend { .attr('tabindex', 0); tabElements - .on('keydown', config._d3compat.eventHandler((d, event) => { + .on('keydown', d3compat.eventHandler((d, event) => { // trigger only if d is an object if (event.keyCode === 13 && typeof d === 'object') { d.chart.legendToggle(d) @@ -252,10 +252,10 @@ export class Legend { event.preventDefault(); } })) - .on('focus', config._d3compat.eventHandler(d => { + .on('focus', d3compat.eventHandler(d => { this._parent.legendHighlight(d); })) - .on('blur', config._d3compat.eventHandler(d => { + .on('blur', d3compat.eventHandler(d => { this._parent.legendReset(d); })); } @@ -277,13 +277,13 @@ export class Legend { .enter() .append('g') .attr('class', 'dc-legend-item') - .on('mouseover', config._d3compat.eventHandler(d => { + .on('mouseover', d3compat.eventHandler(d => { this._parent.legendHighlight(d); })) - .on('mouseout', config._d3compat.eventHandler(d => { + .on('mouseout', d3compat.eventHandler(d => { this._parent.legendReset(d); })) - .on('click', config._d3compat.eventHandler(d => { + .on('click', d3compat.eventHandler(d => { d.chart.legendToggle(d); })); diff --git a/src/charts/pie-chart.js b/src/charts/pie-chart.js index 50f35279e4..70a6063277 100644 --- a/src/charts/pie-chart.js +++ b/src/charts/pie-chart.js @@ -7,7 +7,7 @@ import {CapMixin} from '../base/cap-mixin'; import {ColorMixin} from '../base/color-mixin'; import {BaseMixin} from '../base/base-mixin'; import {transition} from '../core/core'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const DEFAULT_MIN_ANGLE_FOR_LABEL = 0.5; @@ -162,7 +162,7 @@ export class PieChart extends CapMixin(ColorMixin(BaseMixin)) { _createSlicePath (slicesEnter, arcs) { const slicePath = slicesEnter.append('path') .attr('fill', (d, i) => this._fill(d, i)) - .on('click', config._d3compat.eventHandler(d => this._onClick(d))) + .on('click', d3compat.eventHandler(d => this._onClick(d))) .attr('d', (d, i) => this._safeArc(d, i, arcs)); if (this._keyboardAccessible) { @@ -219,11 +219,11 @@ export class PieChart extends CapMixin(ColorMixin(BaseMixin)) { } return classes; }) - .on('click', config._d3compat.eventHandler(d => this._onClick(d))) - .on('mouseover', config._d3compat.eventHandler(d => { + .on('click', d3compat.eventHandler(d => this._onClick(d))) + .on('mouseover', d3compat.eventHandler(d => { this._highlightSlice(d.index, true); })) - .on('mouseout', config._d3compat.eventHandler(d => { + .on('mouseout', d3compat.eventHandler(d => { this._highlightSlice(d.index, false); })); this._positionLabels(labelsEnter, arcs); @@ -243,11 +243,11 @@ export class PieChart extends CapMixin(ColorMixin(BaseMixin)) { .enter() .append('polyline') .attr('class', (d, i) => `pie-path _${i} ${this._sliceCssClass}`) - .on('click', config._d3compat.eventHandler(d => this._onClick(d))) - .on('mouseover', config._d3compat.eventHandler(d => { + .on('click', d3compat.eventHandler(d => this._onClick(d))) + .on('mouseover', d3compat.eventHandler(d => { this._highlightSlice(d.index, true); })) - .on('mouseout', config._d3compat.eventHandler(d => { + .on('mouseout', d3compat.eventHandler(d => { this._highlightSlice(d.index, false); })) .merge(polyline); diff --git a/src/charts/row-chart.js b/src/charts/row-chart.js index 4cc69f07e3..88c1398877 100644 --- a/src/charts/row-chart.js +++ b/src/charts/row-chart.js @@ -6,7 +6,7 @@ import {CapMixin} from '../base/cap-mixin'; import {MarginMixin} from '../base/margin-mixin'; import {ColorMixin} from '../base/color-mixin'; import {transition} from '../core/core'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; /** * Concrete row chart implementation. @@ -191,13 +191,13 @@ export class RowChart extends CapMixin(ColorMixin(MarginMixin)) { const rect = rows.attr('transform', (d, i) => `translate(0,${(i + 1) * this._gap + i * height})`).select('rect') .attr('height', height) .attr('fill', this.getColor) - .on('click', config._d3compat.eventHandler(d => this._onClick(d))) + .on('click', d3compat.eventHandler(d => this._onClick(d))) .classed('dc-tabbable', this._keyboardAccessible) .classed('deselected', d => (this.hasFilter()) ? !this._isSelectedRow(d) : false) .classed('selected', d => (this.hasFilter()) ? this._isSelectedRow(d) : false); if (this._keyboardAccessible) { - this._makeKeyboardAccessible(config._d3compat.eventHandler(d => this._onClick(d))); + this._makeKeyboardAccessible(d3compat.eventHandler(d => this._onClick(d))); } transition(rect, this.transitionDuration(), this.transitionDelay()) @@ -218,12 +218,12 @@ export class RowChart extends CapMixin(ColorMixin(MarginMixin)) { _createLabels (rowEnter) { if (this.renderLabel()) { rowEnter.append('text') - .on('click', config._d3compat.eventHandler(d => this._onClick(d))); + .on('click', d3compat.eventHandler(d => this._onClick(d))); } if (this.renderTitleLabel()) { rowEnter.append('text') .attr('class', this._titleRowCssClass) - .on('click', config._d3compat.eventHandler(d => this._onClick(d))); + .on('click', d3compat.eventHandler(d => this._onClick(d))); } } @@ -233,7 +233,7 @@ export class RowChart extends CapMixin(ColorMixin(MarginMixin)) { .attr('x', this._labelOffsetX) .attr('y', this._labelOffsetY) .attr('dy', this._dyOffset) - .on('click', config._d3compat.eventHandler(d => this._onClick(d))) + .on('click', d3compat.eventHandler(d => this._onClick(d))) .attr('class', (d, i) => `${this._rowCssClass} _${i}`) .text(d => this.label()(d)); transition(lab, this.transitionDuration(), this.transitionDelay()) @@ -245,7 +245,7 @@ export class RowChart extends CapMixin(ColorMixin(MarginMixin)) { .attr('y', this._labelOffsetY) .attr('dy', this._dyOffset) .attr('text-anchor', 'end') - .on('click', config._d3compat.eventHandler(d => this._onClick(d))) + .on('click', d3compat.eventHandler(d => this._onClick(d))) .attr('class', (d, i) => `${this._titleRowCssClass} _${i}`) .text(d => this.title()(d)); transition(titlelab, this.transitionDuration(), this.transitionDelay()) diff --git a/src/charts/select-menu.js b/src/charts/select-menu.js index cb41c917f1..db15b138a8 100644 --- a/src/charts/select-menu.js +++ b/src/charts/select-menu.js @@ -1,7 +1,7 @@ import {events} from '../core/events'; import {BaseMixin} from '../base/base-mixin'; import {logger} from '../core/logger'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; const SELECT_CSS_CLASS = 'dc-select-menu'; const OPTION_CSS_CLASS = 'dc-select-option'; @@ -96,7 +96,7 @@ export class SelectMenu extends BaseMixin { this._select.selectAll(`option.${OPTION_CSS_CLASS}`).sort(this._order); - this._select.on('change', config._d3compat.eventHandler((d, evt) => this._onChange(d, evt))); + this._select.on('change', d3compat.eventHandler((d, evt) => this._onChange(d, evt))); } _onChange (_d, evt) { diff --git a/src/charts/series-chart.js b/src/charts/series-chart.js index a0c9696295..39db66944e 100644 --- a/src/charts/series-chart.js +++ b/src/charts/series-chart.js @@ -3,7 +3,7 @@ import {ascending} from 'd3-array'; import {CompositeChart} from './composite-chart'; import {lineChart} from './line-chart'; import {utils} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; /** * A series chart is a chart that shows multiple series of data overlaid on one chart, where the @@ -56,7 +56,7 @@ export class SeriesChart extends CompositeChart { const keep = []; let childrenChanged; - const nesting = config._d3compat.nester({ + const nesting = d3compat.nester({ key: this._seriesAccessor, sortKeys: this._seriesSort, sortValues: this._valueSort, diff --git a/src/charts/sunburst-chart.js b/src/charts/sunburst-chart.js index 5f19b51173..e7f88f8359 100644 --- a/src/charts/sunburst-chart.js +++ b/src/charts/sunburst-chart.js @@ -7,7 +7,7 @@ import {interpolate} from 'd3-interpolate'; import {transition} from '../core/core'; import {filters} from '../core/filters'; import {utils, pluck} from '../core/utils'; -import {config} from '../core/config'; +import {d3compat} from '../core/config'; import {events} from '../core/events'; import {ColorMixin} from '../base/color-mixin'; import {BaseMixin} from '../base/base-mixin'; @@ -172,7 +172,7 @@ export class SunburstChart extends ColorMixin(BaseMixin) { _createSlicePath (slicesEnter, arcs) { const slicePath = slicesEnter.append('path') .attr('fill', (d, i) => this._fill(d, i)) - .on('click', config._d3compat.eventHandler(d => this.onClick(d))) + .on('click', d3compat.eventHandler(d => this.onClick(d))) .classed('dc-tabbable', this._keyboardAccessible) .attr('d', d => this._safeArc(arcs, d)); @@ -225,7 +225,7 @@ export class SunburstChart extends ColorMixin(BaseMixin) { } return classes; }) - .on('click', config._d3compat.eventHandler(d => this.onClick(d))); + .on('click', d3compat.eventHandler(d => this.onClick(d))); this._positionLabels(labelsEnter, arcs); } } diff --git a/src/core/d3compat-v5.js b/src/compat/d3v5.js similarity index 92% rename from src/core/d3compat-v5.js rename to src/compat/d3v5.js index a0dc7f22be..85819afb57 100644 --- a/src/core/d3compat-v5.js +++ b/src/compat/d3v5.js @@ -3,12 +3,12 @@ import { version } from 'd3'; import { event, mouse } from 'd3-selection'; import { nest } from 'd3-collection'; -import { config } from './config'; +import { d3compat } from '../core/config'; const majorVer = +version[0]; if (majorVer < 6) { - Object.assign(config._d3compat, { + Object.assign(d3compat, { eventHandler: handler => function eventHandler (a ,b) { if (a && a.target) { // d3@v6 - b is __data__, a is the event diff --git a/src/core/d3compat-v6.js b/src/compat/d3v6.js similarity index 93% rename from src/core/d3compat-v6.js rename to src/compat/d3v6.js index cdd5cb73a3..9c4bfcf050 100644 --- a/src/core/d3compat-v6.js +++ b/src/compat/d3v6.js @@ -3,12 +3,12 @@ import { version } from 'd3'; import { pointer } from 'd3-selection'; import { groups } from 'd3-array'; -import { config } from './config'; +import { d3compat } from '../core/config'; const majorVer = +version[0]; if (majorVer > 5) { - Object.assign(config._d3compat, { + Object.assign(d3compat, { eventHandler: handler => function (a, b) { if (a && a.target) { // d3@v6 - b is __data__, a is the event diff --git a/src/core/config.js b/src/core/config.js index 8a2ba9af7d..2a464ee139 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -80,3 +80,8 @@ Config._schemeCategory20c = [ * General configuration object; see {@link Config} for members. */ export const config = new Config(); + +/** + * d3.js compatiblity layer + */ +export const d3compat = {}; diff --git a/src/index-with-version.js b/src/index-with-version.js index d115ea81ae..e2e65b58d6 100644 --- a/src/index-with-version.js +++ b/src/index-with-version.js @@ -2,5 +2,5 @@ export {version} from '../package.json'; export * from './index'; -import './core/d3compat-v5.js'; -import './core/d3compat-v6.js'; \ No newline at end of file +import './compat/d3v5'; +import './compat/d3v6'; \ No newline at end of file diff --git a/web-src/examples/filter-stacks.html b/web-src/examples/filter-stacks.html index 3d05134840..b2e07e58f3 100644 --- a/web-src/examples/filter-stacks.html +++ b/web-src/examples/filter-stacks.html @@ -121,7 +121,7 @@ var key = multikey(d.x, d.layer); return chart.filter() && chart.filters().indexOf(key)===-1; }) - .on('click', dc.config._d3compat.eventHandler(function(d) { + .on('click', dc.d3compat.eventHandler(function(d) { chart.filter(multikey(d.x, d.layer)); dc.redrawAll(); })); From acf1dbd5bf769e6615bfeb7f332ffb0460e9c5f4 Mon Sep 17 00:00:00 2001 From: Patrik Kullman Date: Tue, 6 Apr 2021 21:22:28 +0200 Subject: [PATCH 7/7] fix: move boilerplate compat layer methods --- src/core/config.js | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/core/config.js b/src/core/config.js index 2a464ee139..48b09c47b4 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -18,17 +18,6 @@ export class Config { this._renderlet = null; - this._d3compat = { - eventHandler: handler => function eventHandler (a, b) { - console.warn('No d3.js compatbility event handler registered, defaulting to v6 behavior.'); - handler.call(this, b, a); - }, - nester: ({key, sortKeys, sortValues, entries}) => { - throw new Error('No d3.js compatbility nester registered, load v5 or v6 compability layer.'); - }, - pointer: () => { throw new Error('No d3.js compatbility pointer registered, load v5 or v6 compability layer.'); } - }; - /** * If this boolean is set truthy, all transitions will be disabled, and changes to the charts will happen * immediately. @@ -84,4 +73,13 @@ export const config = new Config(); /** * d3.js compatiblity layer */ -export const d3compat = {}; +export const d3compat = { + eventHandler: handler => function eventHandler (a, b) { + console.warn('No d3.js compatbility event handler registered, defaulting to v6 behavior.'); + handler.call(this, b, a); + }, + nester: ({key, sortKeys, sortValues, entries}) => { + throw new Error('No d3.js compatbility nester registered, load v5 or v6 compability layer.'); + }, + pointer: () => { throw new Error('No d3.js compatbility pointer registered, load v5 or v6 compability layer.'); } +};