diff --git a/.travis.yml b/.travis.yml index 9cb552eb..67c5d8b9 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 diff --git a/CHANGELOG.md b/CHANGELOG.md index ef8fa26a..e2d92dab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,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/docs/configuration.md b/docs/configuration.md index 01c697f2..a12fa6cb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -239,6 +239,60 @@ const chart = eventDrops({ }); ``` +### onMouseOver + +_Default: () => {}_ + +Function to be executed when user moves the mouse on a label. By default, it does nothing. The object for that dropLine is passed as the first argument: + +```js +const chart = eventDrops({ + label: { + onMouseOver: label => { + showTooltip(label); + }, + }, +}); +``` + +Where `label` argument is the `{ "name": "EventDrops, "data": [...] }` etc. depending on configuration. + +This is the function you are looking for if you want to display a tooltip describing the label (either in detail or due to too long name). + +### onMouseOut + +_Default: () => {}_ + +Function to be executed when user moves the mouse out of a label. By default, it does nothing. The object for that dropLine is passed as the first argument: + +```js +const chart = eventDrops({ + label: { + onMouseOut: label => { + hideTooltip(label); + }, + }, +}); +``` + +This is the function you are looking for if you want to hide a tooltip you previously displayed with `onMouseOver`. + +### onClick + +_Default: () => {}_ + +Function to be executed when user clicks on a label. By default, it does nothing. The object for that dropLine is passed as the first argument: + +```js +const chart = eventDrops({ + label: { + onClick: label => { + Console.log(`${label} data is clicked.`); + }, + }, +}); +``` + ## indicator _Default: indicator configuration object_ diff --git a/src/config.js b/src/config.js index 5782aa5c..34831652 100644 --- a/src/config.js +++ b/src/config.js @@ -33,6 +33,9 @@ export default d3 => ({ label: { padding: 20, text: d => `${d.name} (${d.data.length})`, + onMouseOver: () => {}, + onMouseOut: () => {}, + onClick: () => {}, width: 200, }, indicator: { diff --git a/src/dropLine.js b/src/dropLine.js index 859869a7..41a7f158 100644 --- a/src/dropLine.js +++ b/src/dropLine.js @@ -4,7 +4,14 @@ import indicator from './indicator'; export default (config, xScale) => selection => { const { metaballs, - label: { text: labelText, padding: labelPadding, width: labelWidth }, + label: { + text: labelText, + padding: labelPadding, + onMouseOver: labelOnMouseOver, + onMouseOut: labelOnMouseOut, + onClick: labelOnClick, + width: labelWidth, + }, line: { color: lineColor, height: lineHeight }, indicator: indicatorEnabled, } = config; @@ -51,7 +58,10 @@ export default (config, xScale) => selection => { .attr('y', lineHeight / 2) .attr('dy', '0.25em') .attr('text-anchor', 'end') - .text(labelText); + .text(labelText) + .on('mouseover', labelOnMouseOver) + .on('mouseout', labelOnMouseOut) + .on('click', labelOnClick); lines.selectAll('.line-label').text(labelText); lines.selectAll('.drops').call(drop(config, xScale)); diff --git a/src/dropLine.spec.js b/src/dropLine.spec.js index 71cb0aa9..895f7e0f 100644 --- a/src/dropLine.spec.js +++ b/src/dropLine.spec.js @@ -1,5 +1,4 @@ import dropLine from './dropLine'; -import indicator from './indicator'; const defaultConfig = { metaballs: true, @@ -212,6 +211,99 @@ describe('Drop Line', () => { expect(dropsIndex).not.toBe(-1); expect(textIndex > dropsIndex).toBe(true); }); + + it('should call `onMouseOver` configuration listener when hovering a label', () => { + const selection = d3.select('svg').data([[{ name: 'foo' }]]); + + const config = { + ...defaultConfig, + label: { + ...defaultConfig.label, + onMouseOver: jest.fn(), + }, + }; + + dropLine(config, defaultScale)(selection); + + const labelElement = d3.select('.line-label').node(); + const event = new MouseEvent('SVGEvents', {}); + event.initMouseEvent( + 'mouseover', + true, + true, + global, + 0, + 10, + 10, + 10, + 10, + false, + false, + false, + false, + null, + labelElement + ); + labelElement.dispatchEvent(event); + + expect(config.label.onMouseOver).toHaveBeenCalled(); + }); + + it('should call `onMouseOut` configuration listener when blurring a label', () => { + const selection = d3.select('svg').data([[{ name: 'foo' }]]); + + const config = { + ...defaultConfig, + label: { + ...defaultConfig.label, + onMouseOut: jest.fn(), + }, + }; + + dropLine(config, defaultScale)(selection); + + const labelElement = d3.select('.line-label').node(); + const event = new MouseEvent('SVGEvents', {}); + event.initMouseEvent( + 'mouseout', + true, + true, + global, + 0, + 10, + 10, + 10, + 10, + false, + false, + false, + false, + null, + labelElement + ); + labelElement.dispatchEvent(event); + + expect(config.label.onMouseOut).toHaveBeenCalled(); + }); + + it('should call `onClick` configuration listener when clicking on label', () => { + const selection = d3.select('svg').data([[{ name: 'foo' }]]); + + const config = { + ...defaultConfig, + label: { + ...defaultConfig.label, + onClick: jest.fn(), + }, + }; + + dropLine(config, defaultScale)(selection); + + const labelElement = d3.select('.line-label').node(); + labelElement.click(); + + expect(config.label.onClick).toHaveBeenCalled(); + }); }); describe('Indicators', () => {