From a571bb9c9737bd4e75a2f0350108c5b5f9104e4d Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Mon, 13 May 2019 21:29:37 +0100 Subject: [PATCH 1/9] Zoom to domain and id to svg Added zoom to domain function. This allows to zoom to a given domain programmatically. Added id in config, reason for this is that when connecting two EventDrops chart, it is very handy to have the id in the svg element the zoom is happening in. --- README.md | 1 + docs/configuration.md | 6 ++++++ src/config.js | 1 + src/index.js | 43 ++++++++++++++++++++++++++++++++++--------- src/index.spec.js | 34 ++++++++++++++++++++++++++++++++++ src/zoom.js | 16 ++++++++++++++-- src/zoom.spec.js | 42 +++++++++++++++++++++++++++++++++++++++--- 7 files changed, 129 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 809803cd..756b7e35 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ In addition to this configuration object, it also exposes some public members al * **scale()** provides the horizontal scale, allowing you to retrieve bounding dates thanks to `.scale().domain()`, * **filteredData()** returns an object with both `data` and `fullData` keys containing respectively bounds filtered data and full dataset. * **draw(config, scale)** redraws chart using given configuration and `d3.scaleTime` scale +* **zoomToDomain(domain)** programmatically zooms to domain, where domain is `[date, date]` (leftmost date, rightmost date) * **destroy()** execute this function before to removing the chart from DOM. It prevents some memory leaks due to event listeners. * **currentBreakpointLabel** returns current breakpoint (for instance `small`) among a [list of breakpoints](./docs/configuration.md#breakpoints). diff --git a/docs/configuration.md b/docs/configuration.md index 01c697f2..31914646 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -19,6 +19,12 @@ const chart = eventDrops({ d3 }); If you use EventDrops without any module bundler, just include D3 script before EventDrops, and everything should work out of the box. +## id + +_Default: '' (not added to svg)_ + +Convince to add id to the SVG element. This is especially useful if connecting to EventDrops chart together with zoom (through `zoomToDomain`). + ## locale _Default: English locale_ diff --git a/src/config.js b/src/config.js index 5782aa5c..dc84740f 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,7 @@ import enLocale from 'd3-time-format/locale/en-US.json'; export default d3 => ({ + id: '', locale: enLocale, metaballs: { blurDeviation: 10, diff --git a/src/index.js b/src/index.js index d1ab4458..40a00702 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ import bounds from './bounds'; import defaultConfiguration from './config'; import dropLine from './dropLine'; import zoom from './zoom'; +import { getDomainTransform } from './zoom'; import { addMetaballsDefs } from './metaballs'; import './style.css'; @@ -29,6 +30,7 @@ export default ({ ); const { + id, drops, zoom: zoomConfig, drop: { onClick, onMouseOut, onMouseOver }, @@ -62,20 +64,40 @@ export default ({ .attr('width', width) .classed('event-drop-chart', true); + if (id) { + svg.attr('id', id); + } + if (zoomConfig) { - svg.call(zoom(d3, svg, config, xScale, draw, getEvent)); + const zoomObject = d3.zoom(); + svg.call(zoom(d3, svg, config, zoomObject, xScale, draw, getEvent)); + + chart._zoomToDomain = domain => { + const zoomIdentity = getDomainTransform( + d3, + config, + zoomObject, + domain, + xScale, + width + ); + svg.call(zoomObject.transform, zoomIdentity); + }; } if (metaballs) { svg.call(addMetaballsDefs(config)); } - svg.merge(root).attr( - 'height', - d => (d.length + 1) * lineHeight + margin.top + margin.bottom - ); + svg + .merge(root) + .attr( + 'height', + d => (d.length + 1) * lineHeight + margin.top + margin.bottom + ); - svg.append('g') + svg + .append('g') .classed('viewport', true) .attr('transform', `translate(${margin.left},${margin.top})`) .call(draw(config, xScale)); @@ -90,15 +112,18 @@ export default ({ chart.scale = () => chart._scale; chart.filteredData = () => chart._filteredData; + chart.zoomToDomain = domain => { + if (chart._zoomToDomain) { + chart._zoomToDomain(domain); + } + }; chart.destroy = (callback = () => {}) => { global.removeEventListener('resize', chart._initialize, true); callback(); }; const draw = (config, scale) => selection => { - const { - drop: { date: dropDate }, - } = config; + const { drop: { date: dropDate } } = config; const dateBounds = scale.domain().map(d => new Date(d)); const filteredData = selection.data().map(dataSet => { diff --git a/src/index.spec.js b/src/index.spec.js index db16fc03..b50df389 100644 --- a/src/index.spec.js +++ b/src/index.spec.js @@ -24,6 +24,22 @@ describe('EventDrops', () => { resetDom(); }); + it('should add id if present in config', () => { + const config = { + ...defaultConfig, + id: 'test_id', + }; + + const chart = EventDrops(config); + + const root = d3.select('div').data([[{ data: [] }]]); + + root.call(chart); + const svg = document.querySelector('svg'); + + expect(svg.attributes.id.value).toEqual('test_id'); + }); + it('should enable zoom if and only if zoomConfig is not falsy', () => { const test = (zoomConfig, shouldZoomBeCalled) => { resetDom(); @@ -60,6 +76,24 @@ describe('EventDrops', () => { ]); }); + // it('should zoom to correct domain on zoomToDomain', () => { + // const chart = EventDrops({ + // zoom: {}, + // range: { + // start: new Date('2010-01-01'), + // end: new Date('2011-01-01'), + // }, + // }); + // + // const root = d3.select('div').data([[{ data: [] }]]); + // root.call(chart); + // + // const domain = [new Date('2010-04-01'), new Date('2010-09-01')]; + // chart.zoomToDomain(domain); + // + // expect(chart.scale().domain()).toEqual(domain); + // }); + it('should allow to select custom data properties', () => { const chart = EventDrops({ range: { diff --git a/src/zoom.js b/src/zoom.js index d85b2e29..34c49977 100644 --- a/src/zoom.js +++ b/src/zoom.js @@ -15,13 +15,25 @@ export const getShiftedTransform = ( .translate(labelsWidth + labelsPadding, 0); // put origin at its original position }; -export default (d3, svg, config, xScale, draw, getEvent) => { +export function getDomainTransform(d3, config, zoom, domain, xScale, width) { + const { label: { width: labelsWidth, padding: labelsPadding } } = config; + + const fullLabelWidth = labelsWidth + labelsPadding; + // For the reason of two additional translate see getShiftedTransform for explanation + return d3.zoomIdentity + .translate(fullLabelWidth, 0) + .scale((width - labelsWidth) / (xScale(domain[1]) - xScale(domain[0]))) + .translate(-xScale(domain[0]), 0) + .translate(-fullLabelWidth, 0); +} + +export default (d3, svg, config, zoom, xScale, draw, getEvent) => { const { label: { width: labelsWidth, padding: labelsPadding }, zoom: { onZoomStart, onZoom, onZoomEnd, minimumScale, maximumScale }, } = config; - const zoom = d3.zoom().scaleExtent([minimumScale, maximumScale]); + zoom.scaleExtent([minimumScale, maximumScale]); zoom.on('zoom.start', onZoomStart).on('zoom.end', onZoomEnd); diff --git a/src/zoom.spec.js b/src/zoom.spec.js index 9c04c788..0504eb21 100644 --- a/src/zoom.spec.js +++ b/src/zoom.spec.js @@ -1,4 +1,4 @@ -import zoomFactory, { getShiftedTransform } from './zoom'; +import zoomFactory, { getShiftedTransform, getDomainTransform } from './zoom'; const defaultConfig = { label: {}, @@ -10,7 +10,7 @@ describe('Zoom', () => { document.body.appendChild(document.createElement('svg')); }); - describe('getShiftedTransform', () => { + it('should correct shifted transform given original transform', () => { const originalTransform = { x: -120, y: 0, @@ -28,6 +28,41 @@ describe('Zoom', () => { ); }); + it('should transform correctly given domain', () => { + const config = { + ...defaultConfig, + zoom: { + minimumScale: 15, + maximumScale: 25, + }, + label: { width: 100, padding: 50 }, + }; + + const rangeStartEnd = [new Date(2016, 0, 1), new Date(2019, 0, 1)]; + const xScale = d3 + .scaleTime() + .domain(rangeStartEnd) + .range([0, 100]); + + const width = 400; + const zoomObject = d3.zoom(); + const domain = [new Date(2017, 0, 1), new Date(2018, 0, 1)]; + const zoomIdentity = getDomainTransform( + d3, + config, + zoomObject, + domain, + xScale, + width + ); + + expect(zoomIdentity).toEqual({ + k: 9.008219178082191, + x: -1502.054794520548, + y: 0, + }); + }); + it('should set scale extent based on given configuration', () => { const config = { ...defaultConfig, @@ -37,8 +72,9 @@ describe('Zoom', () => { }, }; + const zoomObject = d3.zoom(); const selection = d3.select('svg'); - const zoom = zoomFactory(d3, selection, config); + const zoom = zoomFactory(d3, selection, config, zoomObject); expect(zoom.scaleExtent()).toEqual([15, 25]); }); From 6d9c83b4f34c533c52664f4cdfb2c089f36d7c1a Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Mon, 13 May 2019 22:33:04 +0100 Subject: [PATCH 2/9] Restriction to pan Added the option to restrict panning (dragging behaviour) to the initial date range. So if the date range is from 2010 to 2012, it is not possible to pan to say 2009. If the minimumScale is less than 1, it is possible to zoom out, however panning will be disabled so that it is not possibel to pan to say an earlier date. ZoomToDomain function will ignore this (this is default D3 behaviour). --- README.md | 2 +- docs/configuration.md | 10 ++++++++-- src/config.js | 1 + src/index.js | 16 +++++++++++++++- src/zoom.js | 31 +++++++++++++++++++++++++++++-- src/zoom.spec.js | 35 +++++++++++++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 756b7e35..0e8f34e3 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ In addition to this configuration object, it also exposes some public members al * **scale()** provides the horizontal scale, allowing you to retrieve bounding dates thanks to `.scale().domain()`, * **filteredData()** returns an object with both `data` and `fullData` keys containing respectively bounds filtered data and full dataset. * **draw(config, scale)** redraws chart using given configuration and `d3.scaleTime` scale -* **zoomToDomain(domain)** programmatically zooms to domain, where domain is `[date, date]` (leftmost date, rightmost date) +* **zoomToDomain(domain)** programmatically zooms to domain, where domain is `[date, date]` (leftmost date, rightmost date). Ignores restrictPan modifier (default D3 behaviour). * **destroy()** execute this function before to removing the chart from DOM. It prevents some memory leaks due to event listeners. * **currentBreakpointLabel** returns current breakpoint (for instance `small`) among a [list of breakpoints](./docs/configuration.md#breakpoints). diff --git a/docs/configuration.md b/docs/configuration.md index 31914646..21bb8a55 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -351,7 +351,13 @@ _Default: Infinity_ This parameter configures the maximum zoom level available. Set it to a lower value to prevent your users from zooming in too deeply. -### numberDisplayedTicks +### restrictPan + +_Default: false_ + +If set to `true` will restrict panning (dragging behaviour) to the initial date range. If minimumZoom is set to less than 1, the date range can be zoomed out be larger than the initial. However, after the zoom is less than 1, the pan behaviour is disabled. + +## numberDisplayedTicks \_Default: @@ -368,7 +374,7 @@ const chart = eventDrops({ When reducing chart width, we need to display less labels on the horizontal axis to keep a readable chart. This parameter aims to solve the issue. Hence, on smallest devices, it displays only 3 labels by default at the same time. -### breakpoints +## breakpoints \_Default: diff --git a/src/config.js b/src/config.js index dc84740f..8243598a 100644 --- a/src/config.js +++ b/src/config.js @@ -60,6 +60,7 @@ export default d3 => ({ onZoomEnd: null, minimumScale: 0, maximumScale: Infinity, + restrictPan: false, }, numberDisplayedTicks: { small: 3, diff --git a/src/index.js b/src/index.js index 40a00702..260ac455 100644 --- a/src/index.js +++ b/src/index.js @@ -64,13 +64,27 @@ export default ({ .attr('width', width) .classed('event-drop-chart', true); + const height = parseFloat(svg.style('height')); + if (id) { svg.attr('id', id); } if (zoomConfig) { const zoomObject = d3.zoom(); - svg.call(zoom(d3, svg, config, zoomObject, xScale, draw, getEvent)); + svg.call( + zoom( + d3, + svg, + config, + zoomObject, + xScale, + draw, + getEvent, + width, + height + ) + ); chart._zoomToDomain = domain => { const zoomIdentity = getDomainTransform( diff --git a/src/zoom.js b/src/zoom.js index 34c49977..51965427 100644 --- a/src/zoom.js +++ b/src/zoom.js @@ -27,14 +27,41 @@ export function getDomainTransform(d3, config, zoom, domain, xScale, width) { .translate(-fullLabelWidth, 0); } -export default (d3, svg, config, zoom, xScale, draw, getEvent) => { +export default ( + d3, + svg, + config, + zoom, + xScale, + draw, + getEvent, + width, + height +) => { const { label: { width: labelsWidth, padding: labelsPadding }, - zoom: { onZoomStart, onZoom, onZoomEnd, minimumScale, maximumScale }, + zoom: { + onZoomStart, + onZoom, + onZoomEnd, + minimumScale, + maximumScale, + restrictPan, + }, } = config; + const extentConstraint = [ + [labelsWidth + labelsPadding, 0], + [width, height], + ]; + zoom.scaleExtent([minimumScale, maximumScale]); + //Restricts the pan area to be the specified start/end dates or initial if not set + if (restrictPan) { + zoom.translateExtent(extentConstraint).extent(extentConstraint); + } + zoom.on('zoom.start', onZoomStart).on('zoom.end', onZoomEnd); zoom.on('zoom', args => { diff --git a/src/zoom.spec.js b/src/zoom.spec.js index 0504eb21..7fb6f6af 100644 --- a/src/zoom.spec.js +++ b/src/zoom.spec.js @@ -78,6 +78,41 @@ describe('Zoom', () => { expect(zoom.scaleExtent()).toEqual([15, 25]); }); + it('should set translate extent if restrictPan is true', () => { + const test = (config, translateExtent) => { + const width = 500, + height = 300; + + const selection = d3.select('svg'); + const zoomRestrict = zoomFactory( + d3, + selection, + config, + d3.zoom(), + {}, + {}, + {}, + width, + height + ); + + expect(zoomRestrict.translateExtent()).toEqual(translateExtent); + }; + + const config = { + ...defaultConfig, + label: { + width: 100, + padding: 20, + }, + }; + + test(config, [[-Infinity, -Infinity], [Infinity, Infinity]]); + + config.zoom.restrictPan = true; + test(config, [[120, 0], [500, 300]]); + }); + /* These tests are skipped as I can't find any way to test D3 event at this point. */ it('should update scale according to given D3 zoom event'); it('should redraw chart using newly zoomed scale'); From be26541cf6add5d531add2c9566b7a29cd26172f Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Wed, 15 May 2019 19:04:05 +0100 Subject: [PATCH 3/9] Removed redundant casting to date As we expect the dates to be already formmatted, I don't think it is neccessary to cast them to dates again. --- CHANGELOG.md | 5 +++++ src/isAfter.js | 3 +-- src/isAfter.spec.js | 20 ++++++++++---------- src/isBefore.js | 3 +-- src/isBefore.spec.js | 20 ++++++++++---------- src/withinRange.js | 3 +-- src/withinRange.spec.js | 16 ++++++++-------- 7 files changed, 36 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef8fa26a..3b3cd5ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # CHANGELOG +### 1.4.0 (Unreleased) + +* [#262](https://github.com/marmelab/EventDrops/pull/262): Fixed issue where right bound text would disappear. +* [#259](https://github.com/marmelab/EventDrops/pull/259): Fixed issue where color was flickering and global was undefined. + ### 1.1.x **1.1.2:** diff --git a/src/isAfter.js b/src/isAfter.js index 37c7062d..25e7955b 100644 --- a/src/isAfter.js +++ b/src/isAfter.js @@ -3,6 +3,5 @@ import dateIsAfter from 'date-fns/is_after'; export const isAfter = (date, dateBounds) => { const endingDate = Math.max(...dateBounds); - // @TODO: remove the `new Date()` constructor in the next major version: we need to force it at configuration level. - return dateIsAfter(new Date(date), endingDate); + return dateIsAfter(date, endingDate); }; diff --git a/src/isAfter.spec.js b/src/isAfter.spec.js index 23c1ff9a..a5d06d6d 100644 --- a/src/isAfter.spec.js +++ b/src/isAfter.spec.js @@ -7,11 +7,11 @@ describe('isAfter', () => { expect(isAfter(date, dateRange)).toBe(expectedResult); }; - test('2018-05-19', true); - test('2018-05-01', false); - test('2018-04-19', false); - test('2018-04-01', false); - test('2018-01-01', false); + test(new Date('2018-05-19'), true); + test(new Date('2018-05-01'), false); + test(new Date('2018-04-19'), false); + test(new Date('2018-04-01'), false); + test(new Date('2018-01-01'), false); }); it('should return true if date is after given reverse date range (start date older than end date)', () => { @@ -20,10 +20,10 @@ describe('isAfter', () => { expect(isAfter(date, dateRange)).toBe(expectedResult); }; - test('2018-05-19', true); - test('2018-05-01', false); - test('2018-04-19', false); - test('2018-04-01', false); - test('2018-01-01', false); + test(new Date('2018-05-19'), true); + test(new Date('2018-05-01'), false); + test(new Date('2018-04-19'), false); + test(new Date('2018-04-01'), false); + test(new Date('2018-01-01'), false); }); }); diff --git a/src/isBefore.js b/src/isBefore.js index 3b244a14..7a93affd 100644 --- a/src/isBefore.js +++ b/src/isBefore.js @@ -3,6 +3,5 @@ import dateIsBefore from 'date-fns/is_before'; export const isBefore = (date, dateBounds) => { const startingDate = Math.min(...dateBounds); - // @TODO: remove the `new Date()` constructor in the next major version: we need to force it at configuration level. - return dateIsBefore(new Date(date), startingDate); + return dateIsBefore(date, startingDate); }; diff --git a/src/isBefore.spec.js b/src/isBefore.spec.js index 1621d659..c452dcaf 100644 --- a/src/isBefore.spec.js +++ b/src/isBefore.spec.js @@ -7,11 +7,11 @@ describe('isBefore', () => { expect(isBefore(date, dateRange)).toBe(expectedResult); }; - test('2018-01-01', true); - test('2018-05-19', false); - test('2018-05-01', false); - test('2018-04-19', false); - test('2018-04-01', false); + test(new Date('2018-01-01'), true); + test(new Date('2018-05-19'), false); + test(new Date('2018-05-01'), false); + test(new Date('2018-04-19'), false); + test(new Date('2018-04-01'), false); }); it('should return true if date is before given reverse date range (start date older than end date)', () => { @@ -20,10 +20,10 @@ describe('isBefore', () => { expect(isBefore(date, dateRange)).toBe(expectedResult); }; - test('2018-01-01', true); - test('2018-05-19', false); - test('2018-05-01', false); - test('2018-04-19', false); - test('2018-04-01', false); + test(new Date('2018-01-01'), true); + test(new Date('2018-05-19'), false); + test(new Date('2018-05-01'), false); + test(new Date('2018-04-19'), false); + test(new Date('2018-04-01'), false); }); }); diff --git a/src/withinRange.js b/src/withinRange.js index 12f2de28..fef7b58d 100644 --- a/src/withinRange.js +++ b/src/withinRange.js @@ -4,6 +4,5 @@ export const withinRange = (date, dateBounds) => { const startingDate = Math.min(...dateBounds); const endingDate = Math.max(...dateBounds); - // @TODO: remove the `new Date()` constructor in the next major version: we need to force it at configuration level. - return isWithinRange(new Date(date), startingDate, endingDate); + return isWithinRange(date, startingDate, endingDate); }; diff --git a/src/withinRange.spec.js b/src/withinRange.spec.js index 79207a59..4f2b65a2 100644 --- a/src/withinRange.spec.js +++ b/src/withinRange.spec.js @@ -7,10 +7,10 @@ describe('withinRange', () => { expect(withinRange(date, dateRange)).toBe(expectedResult); }; - test('2018-04-19', true); - test('2018-04-01', true); - test('2018-05-01', true); - test('2018-05-19', false); + test(new Date('2018-04-19'), true); + test(new Date('2018-04-01'), true); + test(new Date('2018-05-01'), true); + test(new Date('2018-05-19'), false); }); it('should return true if date is in given reverse date range (start date older than end date)', () => { @@ -19,9 +19,9 @@ describe('withinRange', () => { expect(withinRange(date, dateRange)).toBe(expectedResult); }; - test('2018-04-19', true); - test('2018-04-01', true); - test('2018-05-01', true); - test('2018-05-19', false); + test(new Date('2018-04-19'), true); + test(new Date('2018-04-01'), true); + test(new Date('2018-05-01'), true); + test(new Date('2018-05-19'), false); }); }); From 9d6ac891b9be31b57e7d210da3ef71d3b1dc8c49 Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Wed, 15 May 2019 19:31:41 +0100 Subject: [PATCH 4/9] Optional transition on zoom Added optional arguments to zoomToDomain to allow for transition. --- README.md | 2 +- src/index.js | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0e8f34e3..99da4f10 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ In addition to this configuration object, it also exposes some public members al * **scale()** provides the horizontal scale, allowing you to retrieve bounding dates thanks to `.scale().domain()`, * **filteredData()** returns an object with both `data` and `fullData` keys containing respectively bounds filtered data and full dataset. * **draw(config, scale)** redraws chart using given configuration and `d3.scaleTime` scale -* **zoomToDomain(domain)** programmatically zooms to domain, where domain is `[date, date]` (leftmost date, rightmost date). Ignores restrictPan modifier (default D3 behaviour). +* **zoomToDomain(domain, duration = 0, delay = 0, ease = d3.easeLinear)** programmatically zooms to domain, where domain is `[date, date]` (leftmost date, rightmost date). Ignores restrictPan modifier (default D3 behaviour). By default there is no transition as duration is 0, however this can be tweaked to allow for a more visual appealing zoom. * **destroy()** execute this function before to removing the chart from DOM. It prevents some memory leaks due to event listeners. * **currentBreakpointLabel** returns current breakpoint (for instance `small`) among a [list of breakpoints](./docs/configuration.md#breakpoints). diff --git a/src/index.js b/src/index.js index 260ac455..8d0d4639 100644 --- a/src/index.js +++ b/src/index.js @@ -86,7 +86,7 @@ export default ({ ) ); - chart._zoomToDomain = domain => { + chart._zoomToDomain = (domain, duration, delay, ease) => { const zoomIdentity = getDomainTransform( d3, config, @@ -95,7 +95,12 @@ export default ({ xScale, width ); - svg.call(zoomObject.transform, zoomIdentity); + svg + .transition() + .ease(ease) + .delay(delay) + .duration(duration) + .call(zoomObject.transform, zoomIdentity); }; } @@ -126,9 +131,14 @@ export default ({ chart.scale = () => chart._scale; chart.filteredData = () => chart._filteredData; - chart.zoomToDomain = domain => { + chart.zoomToDomain = ( + domain, + duration = 0, + delay = 0, + ease = d3.easeLinear + ) => { if (chart._zoomToDomain) { - chart._zoomToDomain(domain); + chart._zoomToDomain(domain, duration, delay, ease); } }; chart.destroy = (callback = () => {}) => { From a0c6cb9557f5487e4329b41e69edd529241abb8e Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Sun, 19 May 2019 22:39:47 +0100 Subject: [PATCH 5/9] Attempting to fix CI --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9cb552eb..aab9d357 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,10 @@ sudo: false +dist: xenial language: node_js node_js: - - 6.9 + - 10.15.3 addons: - firefox: "50.0.2" + firefox: latest cache: directories: - node_modules @@ -14,8 +15,8 @@ install: - npm install before_script: - "export DISPLAY=:99.0" - - "sh -e /etc/init.d/xvfb start" - - sleep 3 # give xvfb some time to start - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16" script: - make test +services: + - xvfb \ No newline at end of file From 28d0058be0685d7f1be8034791d67ae3f6a0a4c3 Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Fri, 24 May 2019 16:04:25 +0100 Subject: [PATCH 6/9] Removed id and review changes Removed id as this is simple to add manually. Chnaged to restrictPan to restrictpan so it could be referenced in MD file (if someone knows how to reference in uppercase, please change). Added in a check to see if _zoomToDomain is defined as function, if not then throw error. Renamed zoomObject to zoom as it is more consistent with other D3 example code. Zoom is now zoomFactory. Removed unused code in test for index. Changelog, configuration doc and Readme updated. --- CHANGELOG.md | 40 ++++++++++++++++++++++++---------------- README.md | 12 ++++++------ docs/configuration.md | 8 +------- src/config.js | 3 +-- src/index.js | 23 +++++++++++------------ src/index.spec.js | 34 ---------------------------------- src/zoom.js | 4 ++-- src/zoom.spec.js | 2 +- 8 files changed, 46 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b3cd5ce..1345d811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,16 @@ ### 1.4.0 (Unreleased) -* [#262](https://github.com/marmelab/EventDrops/pull/262): Fixed issue where right bound text would disappear. -* [#259](https://github.com/marmelab/EventDrops/pull/259): Fixed issue where color was flickering and global was undefined. +[#269](https://github.com/marmelab/EventDrops/pull/269): + +* Removed `new Date()` in isAfter, isBefore and withinRange (objects were already a date). +* Fixed TravisCI build. +* Restrict panning. Option in config to restrict the zooming and panning, so it will only be between start and end in range. +* Zoom to domain. Exposed a function to zoom to domain, as well as the option to add in a transition. + +[#262](https://github.com/marmelab/EventDrops/pull/262): Fixed issue where right bound text would disappear. + +[#259](https://github.com/marmelab/EventDrops/pull/259): Fixed issue where color was flickering and global was undefined. ### 1.1.x @@ -33,25 +41,25 @@ ## 1.0.0 -* Huge performance boost (almost 10 times faster when zooming or panning) -* Review configuration to get more intuitive naming -* Simplify tick format configuration passing only time formats instead of a whole function -* Fix zoom and panning center -* Better integration with module bundlers (allowing to pass a local D3 object instead of the global one) +* Huge performance boost (almost 10 times faster when zooming or panning) +* Review configuration to get more intuitive naming +* Simplify tick format configuration passing only time formats instead of a whole function +* Fix zoom and panning center +* Better integration with module bundlers (allowing to pass a local D3 object instead of the global one) We took profit of this major version change to improve the API - unfortunately, we couldn't keep backwards compatibility. See the [migration guide](./MIGRATION-4.0.md) for more informations. ## 0.3.0 -* API Change: The data for each event line object must now be in the `data` property (was `date`). -* Pass any data object to each drop and specify the date property with a callback. -* The SVG is now responsive and fit with its parent -* Rename `eventHover`, `eventClick` and `eventZoom` events to `mouseover`, `click` and `zoomend` respectively. -* Adding `mouseout` handler +* API Change: The data for each event line object must now be in the `data` property (was `date`). +* Pass any data object to each drop and specify the date property with a callback. +* The SVG is now responsive and fit with its parent +* Rename `eventHover`, `eventClick` and `eventZoom` events to `mouseover`, `click` and `zoomend` respectively. +* Adding `mouseout` handler ## 0.2.0 -* Display metaballs by default instead of simple dots -* Adding `eventClick` event handler on drops -* Use of Webpack instead of Babel for development tasks -* Full rewrite of the code base for better code splitting (may cause some BC breaks) +* Display metaballs by default instead of simple dots +* Adding `eventClick` event handler on drops +* Use of Webpack instead of Babel for development tasks +* Full rewrite of the code base for better code splitting (may cause some BC breaks) diff --git a/README.md b/README.md index 99da4f10..b265f6ed 100644 --- a/README.md +++ b/README.md @@ -84,12 +84,12 @@ You can either use D3 as a specific import (specifying it in first argument of ` In addition to this configuration object, it also exposes some public members allowing you to customize your application based on filtered data: -* **scale()** provides the horizontal scale, allowing you to retrieve bounding dates thanks to `.scale().domain()`, -* **filteredData()** returns an object with both `data` and `fullData` keys containing respectively bounds filtered data and full dataset. -* **draw(config, scale)** redraws chart using given configuration and `d3.scaleTime` scale -* **zoomToDomain(domain, duration = 0, delay = 0, ease = d3.easeLinear)** programmatically zooms to domain, where domain is `[date, date]` (leftmost date, rightmost date). Ignores restrictPan modifier (default D3 behaviour). By default there is no transition as duration is 0, however this can be tweaked to allow for a more visual appealing zoom. -* **destroy()** execute this function before to removing the chart from DOM. It prevents some memory leaks due to event listeners. -* **currentBreakpointLabel** returns current breakpoint (for instance `small`) among a [list of breakpoints](./docs/configuration.md#breakpoints). +* **scale()** provides the horizontal scale, allowing you to retrieve bounding dates thanks to `.scale().domain()`, +* **filteredData()** returns an object with both `data` and `fullData` keys containing respectively bounds filtered data and full dataset. +* **draw(config, scale)** redraws chart using given configuration and `d3.scaleTime` scale +* **zoomToDomain(domain, duration = 0, delay = 0, ease = d3.easeLinear)** programmatically zooms to domain, where domain is `[date, date]` (leftmost date, rightmost date). Ignores [restrictPan](./docs/configuration.md#restrictpan) modifier; if set to true, the function can still zoom out of restriction. By default there is no transition as duration is 0, however this can be tweaked to allow for a more visual appealing zoom. +* **destroy()** execute this function before to removing the chart from DOM. It prevents some memory leaks due to event listeners. +* **currentBreakpointLabel** returns current breakpoint (for instance `small`) among a [list of breakpoints](./docs/configuration.md#breakpoints). Hence, if you want to display number of displayed data and time bounds as in the [demo](https://marmelab.com/EventDrops/), you can use the following code: diff --git a/docs/configuration.md b/docs/configuration.md index 21bb8a55..8c021d97 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -19,12 +19,6 @@ const chart = eventDrops({ d3 }); If you use EventDrops without any module bundler, just include D3 script before EventDrops, and everything should work out of the box. -## id - -_Default: '' (not added to svg)_ - -Convince to add id to the SVG element. This is especially useful if connecting to EventDrops chart together with zoom (through `zoomToDomain`). - ## locale _Default: English locale_ @@ -351,7 +345,7 @@ _Default: Infinity_ This parameter configures the maximum zoom level available. Set it to a lower value to prevent your users from zooming in too deeply. -### restrictPan +### restrictpan _Default: false_ diff --git a/src/config.js b/src/config.js index 8243598a..c7fcbaae 100644 --- a/src/config.js +++ b/src/config.js @@ -1,7 +1,6 @@ import enLocale from 'd3-time-format/locale/en-US.json'; export default d3 => ({ - id: '', locale: enLocale, metaballs: { blurDeviation: 10, @@ -60,7 +59,7 @@ export default d3 => ({ onZoomEnd: null, minimumScale: 0, maximumScale: Infinity, - restrictPan: false, + restrictpan: false, }, numberDisplayedTicks: { small: 3, diff --git a/src/index.js b/src/index.js index 8d0d4639..bed81699 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,7 @@ import { getBreakpointLabel } from './breakpoint'; import bounds from './bounds'; import defaultConfiguration from './config'; import dropLine from './dropLine'; -import zoom from './zoom'; +import zoomFactory from './zoom'; import { getDomainTransform } from './zoom'; import { addMetaballsDefs } from './metaballs'; @@ -30,7 +30,6 @@ export default ({ ); const { - id, drops, zoom: zoomConfig, drop: { onClick, onMouseOut, onMouseOver }, @@ -66,18 +65,14 @@ export default ({ const height = parseFloat(svg.style('height')); - if (id) { - svg.attr('id', id); - } - if (zoomConfig) { - const zoomObject = d3.zoom(); + const zoom = d3.zoom(); svg.call( - zoom( + zoomFactory( d3, svg, config, - zoomObject, + zoom, xScale, draw, getEvent, @@ -90,7 +85,7 @@ export default ({ const zoomIdentity = getDomainTransform( d3, config, - zoomObject, + zoom, domain, xScale, width @@ -100,7 +95,7 @@ export default ({ .ease(ease) .delay(delay) .duration(duration) - .call(zoomObject.transform, zoomIdentity); + .call(zoom.transform, zoomIdentity); }; } @@ -137,8 +132,12 @@ export default ({ delay = 0, ease = d3.easeLinear ) => { - if (chart._zoomToDomain) { + if (typeof chart._zoomToDomain === 'function') { chart._zoomToDomain(domain, duration, delay, ease); + } else { + throw new Error( + 'Calling "zoomToDomain" requires zooming to be enabled.' + ); } }; chart.destroy = (callback = () => {}) => { diff --git a/src/index.spec.js b/src/index.spec.js index b50df389..db16fc03 100644 --- a/src/index.spec.js +++ b/src/index.spec.js @@ -24,22 +24,6 @@ describe('EventDrops', () => { resetDom(); }); - it('should add id if present in config', () => { - const config = { - ...defaultConfig, - id: 'test_id', - }; - - const chart = EventDrops(config); - - const root = d3.select('div').data([[{ data: [] }]]); - - root.call(chart); - const svg = document.querySelector('svg'); - - expect(svg.attributes.id.value).toEqual('test_id'); - }); - it('should enable zoom if and only if zoomConfig is not falsy', () => { const test = (zoomConfig, shouldZoomBeCalled) => { resetDom(); @@ -76,24 +60,6 @@ describe('EventDrops', () => { ]); }); - // it('should zoom to correct domain on zoomToDomain', () => { - // const chart = EventDrops({ - // zoom: {}, - // range: { - // start: new Date('2010-01-01'), - // end: new Date('2011-01-01'), - // }, - // }); - // - // const root = d3.select('div').data([[{ data: [] }]]); - // root.call(chart); - // - // const domain = [new Date('2010-04-01'), new Date('2010-09-01')]; - // chart.zoomToDomain(domain); - // - // expect(chart.scale().domain()).toEqual(domain); - // }); - it('should allow to select custom data properties', () => { const chart = EventDrops({ range: { diff --git a/src/zoom.js b/src/zoom.js index 51965427..08e2aeae 100644 --- a/src/zoom.js +++ b/src/zoom.js @@ -46,7 +46,7 @@ export default ( onZoomEnd, minimumScale, maximumScale, - restrictPan, + restrictpan, }, } = config; @@ -58,7 +58,7 @@ export default ( zoom.scaleExtent([minimumScale, maximumScale]); //Restricts the pan area to be the specified start/end dates or initial if not set - if (restrictPan) { + if (restrictpan) { zoom.translateExtent(extentConstraint).extent(extentConstraint); } diff --git a/src/zoom.spec.js b/src/zoom.spec.js index 7fb6f6af..701e20e7 100644 --- a/src/zoom.spec.js +++ b/src/zoom.spec.js @@ -109,7 +109,7 @@ describe('Zoom', () => { test(config, [[-Infinity, -Infinity], [Infinity, Infinity]]); - config.zoom.restrictPan = true; + config.zoom.restrictpan = true; test(config, [[120, 0], [500, 300]]); }); From 40cf68a073b92a83f51ec37c0312bd922ecdeaa3 Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Fri, 24 May 2019 16:24:34 +0100 Subject: [PATCH 7/9] Forgot to add travis file, added new line --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index aab9d357..40b4523e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,4 +19,4 @@ before_script: script: - make test services: - - xvfb \ No newline at end of file + - xvfb From 9d6fb72d52c55965dbf3c17c1cee9491bfbfc8d3 Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Wed, 28 Aug 2019 19:38:45 +0100 Subject: [PATCH 8/9] Reverted date changes. Added jsDoc and removed unused param --- CHANGELOG.md | 41 ++++++++++++++--------------------------- src/index.js | 21 +++++++++------------ src/isAfter.js | 3 ++- src/isAfter.spec.js | 20 ++++++++++---------- src/isBefore.js | 3 ++- src/isBefore.spec.js | 20 ++++++++++---------- src/withinRange.js | 3 ++- src/withinRange.spec.js | 16 ++++++++-------- src/zoom.js | 23 +++++++++++++++++++++-- src/zoom.spec.js | 2 -- 10 files changed, 78 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1345d811..e2d92dab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,5 @@ # CHANGELOG -### 1.4.0 (Unreleased) - -[#269](https://github.com/marmelab/EventDrops/pull/269): - -* Removed `new Date()` in isAfter, isBefore and withinRange (objects were already a date). -* Fixed TravisCI build. -* Restrict panning. Option in config to restrict the zooming and panning, so it will only be between start and end in range. -* Zoom to domain. Exposed a function to zoom to domain, as well as the option to add in a transition. - -[#262](https://github.com/marmelab/EventDrops/pull/262): Fixed issue where right bound text would disappear. - -[#259](https://github.com/marmelab/EventDrops/pull/259): Fixed issue where color was flickering and global was undefined. - ### 1.1.x **1.1.2:** @@ -41,25 +28,25 @@ ## 1.0.0 -* Huge performance boost (almost 10 times faster when zooming or panning) -* Review configuration to get more intuitive naming -* Simplify tick format configuration passing only time formats instead of a whole function -* Fix zoom and panning center -* Better integration with module bundlers (allowing to pass a local D3 object instead of the global one) +- Huge performance boost (almost 10 times faster when zooming or panning) +- Review configuration to get more intuitive naming +- Simplify tick format configuration passing only time formats instead of a whole function +- Fix zoom and panning center +- Better integration with module bundlers (allowing to pass a local D3 object instead of the global one) We took profit of this major version change to improve the API - unfortunately, we couldn't keep backwards compatibility. See the [migration guide](./MIGRATION-4.0.md) for more informations. ## 0.3.0 -* API Change: The data for each event line object must now be in the `data` property (was `date`). -* Pass any data object to each drop and specify the date property with a callback. -* The SVG is now responsive and fit with its parent -* Rename `eventHover`, `eventClick` and `eventZoom` events to `mouseover`, `click` and `zoomend` respectively. -* Adding `mouseout` handler +- API Change: The data for each event line object must now be in the `data` property (was `date`). +- Pass any data object to each drop and specify the date property with a callback. +- The SVG is now responsive and fit with its parent +- Rename `eventHover`, `eventClick` and `eventZoom` events to `mouseover`, `click` and `zoomend` respectively. +- Adding `mouseout` handler ## 0.2.0 -* Display metaballs by default instead of simple dots -* Adding `eventClick` event handler on drops -* Use of Webpack instead of Babel for development tasks -* Full rewrite of the code base for better code splitting (may cause some BC breaks) +- Display metaballs by default instead of simple dots +- Adding `eventClick` event handler on drops +- Use of Webpack instead of Babel for development tasks +- Full rewrite of the code base for better code splitting (may cause some BC breaks) diff --git a/src/index.js b/src/index.js index bed81699..ebbba39a 100644 --- a/src/index.js +++ b/src/index.js @@ -85,13 +85,11 @@ export default ({ const zoomIdentity = getDomainTransform( d3, config, - zoom, domain, xScale, width ); - svg - .transition() + svg.transition() .ease(ease) .delay(delay) .duration(duration) @@ -103,15 +101,12 @@ export default ({ svg.call(addMetaballsDefs(config)); } - svg - .merge(root) - .attr( - 'height', - d => (d.length + 1) * lineHeight + margin.top + margin.bottom - ); + svg.merge(root).attr( + 'height', + d => (d.length + 1) * lineHeight + margin.top + margin.bottom + ); - svg - .append('g') + svg.append('g') .classed('viewport', true) .attr('transform', `translate(${margin.left},${margin.top})`) .call(draw(config, xScale)); @@ -146,7 +141,9 @@ export default ({ }; const draw = (config, scale) => selection => { - const { drop: { date: dropDate } } = config; + const { + drop: { date: dropDate }, + } = config; const dateBounds = scale.domain().map(d => new Date(d)); const filteredData = selection.data().map(dataSet => { diff --git a/src/isAfter.js b/src/isAfter.js index 25e7955b..37c7062d 100644 --- a/src/isAfter.js +++ b/src/isAfter.js @@ -3,5 +3,6 @@ import dateIsAfter from 'date-fns/is_after'; export const isAfter = (date, dateBounds) => { const endingDate = Math.max(...dateBounds); - return dateIsAfter(date, endingDate); + // @TODO: remove the `new Date()` constructor in the next major version: we need to force it at configuration level. + return dateIsAfter(new Date(date), endingDate); }; diff --git a/src/isAfter.spec.js b/src/isAfter.spec.js index a5d06d6d..23c1ff9a 100644 --- a/src/isAfter.spec.js +++ b/src/isAfter.spec.js @@ -7,11 +7,11 @@ describe('isAfter', () => { expect(isAfter(date, dateRange)).toBe(expectedResult); }; - test(new Date('2018-05-19'), true); - test(new Date('2018-05-01'), false); - test(new Date('2018-04-19'), false); - test(new Date('2018-04-01'), false); - test(new Date('2018-01-01'), false); + test('2018-05-19', true); + test('2018-05-01', false); + test('2018-04-19', false); + test('2018-04-01', false); + test('2018-01-01', false); }); it('should return true if date is after given reverse date range (start date older than end date)', () => { @@ -20,10 +20,10 @@ describe('isAfter', () => { expect(isAfter(date, dateRange)).toBe(expectedResult); }; - test(new Date('2018-05-19'), true); - test(new Date('2018-05-01'), false); - test(new Date('2018-04-19'), false); - test(new Date('2018-04-01'), false); - test(new Date('2018-01-01'), false); + test('2018-05-19', true); + test('2018-05-01', false); + test('2018-04-19', false); + test('2018-04-01', false); + test('2018-01-01', false); }); }); diff --git a/src/isBefore.js b/src/isBefore.js index 7a93affd..3b244a14 100644 --- a/src/isBefore.js +++ b/src/isBefore.js @@ -3,5 +3,6 @@ import dateIsBefore from 'date-fns/is_before'; export const isBefore = (date, dateBounds) => { const startingDate = Math.min(...dateBounds); - return dateIsBefore(date, startingDate); + // @TODO: remove the `new Date()` constructor in the next major version: we need to force it at configuration level. + return dateIsBefore(new Date(date), startingDate); }; diff --git a/src/isBefore.spec.js b/src/isBefore.spec.js index c452dcaf..1621d659 100644 --- a/src/isBefore.spec.js +++ b/src/isBefore.spec.js @@ -7,11 +7,11 @@ describe('isBefore', () => { expect(isBefore(date, dateRange)).toBe(expectedResult); }; - test(new Date('2018-01-01'), true); - test(new Date('2018-05-19'), false); - test(new Date('2018-05-01'), false); - test(new Date('2018-04-19'), false); - test(new Date('2018-04-01'), false); + test('2018-01-01', true); + test('2018-05-19', false); + test('2018-05-01', false); + test('2018-04-19', false); + test('2018-04-01', false); }); it('should return true if date is before given reverse date range (start date older than end date)', () => { @@ -20,10 +20,10 @@ describe('isBefore', () => { expect(isBefore(date, dateRange)).toBe(expectedResult); }; - test(new Date('2018-01-01'), true); - test(new Date('2018-05-19'), false); - test(new Date('2018-05-01'), false); - test(new Date('2018-04-19'), false); - test(new Date('2018-04-01'), false); + test('2018-01-01', true); + test('2018-05-19', false); + test('2018-05-01', false); + test('2018-04-19', false); + test('2018-04-01', false); }); }); diff --git a/src/withinRange.js b/src/withinRange.js index fef7b58d..12f2de28 100644 --- a/src/withinRange.js +++ b/src/withinRange.js @@ -4,5 +4,6 @@ export const withinRange = (date, dateBounds) => { const startingDate = Math.min(...dateBounds); const endingDate = Math.max(...dateBounds); - return isWithinRange(date, startingDate, endingDate); + // @TODO: remove the `new Date()` constructor in the next major version: we need to force it at configuration level. + return isWithinRange(new Date(date), startingDate, endingDate); }; diff --git a/src/withinRange.spec.js b/src/withinRange.spec.js index 4f2b65a2..79207a59 100644 --- a/src/withinRange.spec.js +++ b/src/withinRange.spec.js @@ -7,10 +7,10 @@ describe('withinRange', () => { expect(withinRange(date, dateRange)).toBe(expectedResult); }; - test(new Date('2018-04-19'), true); - test(new Date('2018-04-01'), true); - test(new Date('2018-05-01'), true); - test(new Date('2018-05-19'), false); + test('2018-04-19', true); + test('2018-04-01', true); + test('2018-05-01', true); + test('2018-05-19', false); }); it('should return true if date is in given reverse date range (start date older than end date)', () => { @@ -19,9 +19,9 @@ describe('withinRange', () => { expect(withinRange(date, dateRange)).toBe(expectedResult); }; - test(new Date('2018-04-19'), true); - test(new Date('2018-04-01'), true); - test(new Date('2018-05-01'), true); - test(new Date('2018-05-19'), false); + test('2018-04-19', true); + test('2018-04-01', true); + test('2018-05-01', true); + test('2018-05-19', false); }); }); diff --git a/src/zoom.js b/src/zoom.js index 08e2aeae..2895c85a 100644 --- a/src/zoom.js +++ b/src/zoom.js @@ -15,8 +15,27 @@ export const getShiftedTransform = ( .translate(labelsWidth + labelsPadding, 0); // put origin at its original position }; -export function getDomainTransform(d3, config, zoom, domain, xScale, width) { - const { label: { width: labelsWidth, padding: labelsPadding } } = config; +/** + * Given a domain, return a zoomIdentity (transformation) which can be called to zoom to that domain. + * Translates in reverse direction of the labels before applying the zoom and resets after, + * which factors out the label when creating zoom. + * + * @param {Object} d3 d3 object + * @param {Object} config configuration + * @param {Object[]} domain `[date, date]` where first and second is first date and last to zoom to respectively + * @param {Object} xScale a d3 scaleTime + * @param {number} width Width of the chart + * @returns {Object} transform object with x, y, and k (scale) + * + * @see https://github.com/d3/d3-zoom#zoomIdentity + * @example + * const transform = getDomainTransform(d3, config, domain, xScale, 1000); + * //transform: { x: 1.234, y: 0.323, k: 2.34 } + */ +export function getDomainTransform(d3, config, domain, xScale, width) { + const { + label: { width: labelsWidth, padding: labelsPadding }, + } = config; const fullLabelWidth = labelsWidth + labelsPadding; // For the reason of two additional translate see getShiftedTransform for explanation diff --git a/src/zoom.spec.js b/src/zoom.spec.js index 701e20e7..92eda90e 100644 --- a/src/zoom.spec.js +++ b/src/zoom.spec.js @@ -45,12 +45,10 @@ describe('Zoom', () => { .range([0, 100]); const width = 400; - const zoomObject = d3.zoom(); const domain = [new Date(2017, 0, 1), new Date(2018, 0, 1)]; const zoomIdentity = getDomainTransform( d3, config, - zoomObject, domain, xScale, width From b5c5a7cf66a2045fe580cbe5120474568f70d3a3 Mon Sep 17 00:00:00 2001 From: Haakon Thor Brunstad Date: Thu, 29 Aug 2019 18:29:24 +0100 Subject: [PATCH 9/9] Fixed typo restrictPan --- docs/configuration.md | 2 +- src/config.js | 2 +- src/zoom.js | 8 +++----- src/zoom.spec.js | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 8c021d97..3ae44765 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -345,7 +345,7 @@ _Default: Infinity_ This parameter configures the maximum zoom level available. Set it to a lower value to prevent your users from zooming in too deeply. -### restrictpan +### restrictPan _Default: false_ diff --git a/src/config.js b/src/config.js index c7fcbaae..5254d5c3 100644 --- a/src/config.js +++ b/src/config.js @@ -59,7 +59,7 @@ export default d3 => ({ onZoomEnd: null, minimumScale: 0, maximumScale: Infinity, - restrictpan: false, + restrictPan: false, }, numberDisplayedTicks: { small: 3, diff --git a/src/zoom.js b/src/zoom.js index 2895c85a..989b9e00 100644 --- a/src/zoom.js +++ b/src/zoom.js @@ -33,9 +33,7 @@ export const getShiftedTransform = ( * //transform: { x: 1.234, y: 0.323, k: 2.34 } */ export function getDomainTransform(d3, config, domain, xScale, width) { - const { - label: { width: labelsWidth, padding: labelsPadding }, - } = config; + const { label: { width: labelsWidth, padding: labelsPadding } } = config; const fullLabelWidth = labelsWidth + labelsPadding; // For the reason of two additional translate see getShiftedTransform for explanation @@ -65,7 +63,7 @@ export default ( onZoomEnd, minimumScale, maximumScale, - restrictpan, + restrictPan, }, } = config; @@ -77,7 +75,7 @@ export default ( zoom.scaleExtent([minimumScale, maximumScale]); //Restricts the pan area to be the specified start/end dates or initial if not set - if (restrictpan) { + if (restrictPan) { zoom.translateExtent(extentConstraint).extent(extentConstraint); } diff --git a/src/zoom.spec.js b/src/zoom.spec.js index 92eda90e..c2d3da26 100644 --- a/src/zoom.spec.js +++ b/src/zoom.spec.js @@ -107,7 +107,7 @@ describe('Zoom', () => { test(config, [[-Infinity, -Infinity], [Infinity, Infinity]]); - config.zoom.restrictpan = true; + config.zoom.restrictPan = true; test(config, [[120, 0], [500, 300]]); });