Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add drag&drop support to vaadin-chart #8488

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/charts/src/vaadin-chart.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,21 @@ export type ChartPointUnselectEvent = CustomEvent<{ point: Point; originalEvent:
*/
export type ChartPointUpdateEvent = CustomEvent<{ point: Point; originalEvent: ChartPointEvent }>;

/**
* Fired when starting to drag a point.
*/
export type ChartPointDragStartEvent = CustomEvent<{ point: Point; originalEvent: ChartPointEvent }>;

/**
* Fired when the point is dropped.
*/
export type ChartPointDropEvent = CustomEvent<{ point: Point; originalEvent: ChartPointEvent }>;

/**
* Fired while dragging a point.
*/
export type ChartPointDragEvent = CustomEvent<{ point: Point; originalEvent: ChartPointEvent }>;

/**
* Fired when when the minimum and maximum is set for the X axis.
*/
Expand Down Expand Up @@ -245,6 +260,12 @@ export interface ChartCustomEventMap {

'point-update': ChartPointUpdateEvent;

'point-drag-start': ChartPointDragStartEvent;

'point-drop': ChartPointDropEvent;

'point-drag': ChartPointDragEvent;

'xaxes-extremes-set': ChartXaxesExtremesSetEvent;

'yaxes-extremes-set': ChartYaxesExtremesSetEvent;
Expand Down Expand Up @@ -404,6 +425,9 @@ export type ChartEventMap = ChartCustomEventMap & HTMLElementEventMap;
* @fires {CustomEvent} point-select -Fired when the point is selected either programmatically or by clicking on the point.
* @fires {CustomEvent} point-unselect - Fired when the point is unselected either programmatically or by clicking on the point.
* @fires {CustomEvent} point-update - Fired when the point is updated programmatically through `.updateConfiguration()` method.
* @fires {CustomEvent} point-drag-start - Fired when starting to drag a point.
* @fires {CustomEvent} point-drop - Fired when the point is dropped.
* @fires {CustomEvent} point-drag - Fired while dragging a point.
* @fires {CustomEvent} xaxes-extremes-set - Fired when when the minimum and maximum is set for the X axis.
* @fires {CustomEvent} yaxes-extremes-set - Fired when when the minimum and maximum is set for the Y axis.
*/
Expand Down
63 changes: 49 additions & 14 deletions packages/charts/src/vaadin-chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import 'highcharts/es-modules/masters/modules/organization.src.js';
import 'highcharts/es-modules/masters/modules/xrange.src.js';
import 'highcharts/es-modules/masters/modules/bullet.src.js';
import 'highcharts/es-modules/masters/modules/gantt.src.js';
import 'highcharts/es-modules/masters/modules/draggable-points.src.js';
import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
import { beforeNextRender } from '@polymer/polymer/lib/utils/render-status.js';
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
Expand Down Expand Up @@ -250,6 +251,9 @@ Highcharts.setOptions({ lang: { noData: '' } });
* @fires {CustomEvent} point-select -Fired when the point is selected either programmatically or by clicking on the point.
* @fires {CustomEvent} point-unselect - Fired when the point is unselected either programmatically or by clicking on the point.
* @fires {CustomEvent} point-update - Fired when the point is updated programmatically through `.updateConfiguration()` method.
* @fires {CustomEvent} point-drag-start - Fired when starting to drag a point.
* @fires {CustomEvent} point-drop - Fired when the point is dropped.
* @fires {CustomEvent} point-drag - Fired while dragging a point.
* @fires {CustomEvent} xaxes-extremes-set - Fired when when the minimum and maximum is set for the X axis.
* @fires {CustomEvent} yaxes-extremes-set - Fired when when the minimum and maximum is set for the Y axis.
*
Expand Down Expand Up @@ -885,6 +889,30 @@ class Chart extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement))) {
* @param {Object} point Point object where the event was sent from
*/
update: 'point-update',

/**
* Fired when starting to drag a point.
* @event point-drag-start
* @param {Object} detail.originalEvent object with details about the event sent
* @param {Object} point Point object where the event was sent from
*/
dragStart: 'point-drag-start',

/**
* Fired when the point is dropped.
* @event point-drop
* @param {Object} detail.originalEvent object with details about the event sent
* @param {Object} point Point object where the event was sent from
*/
drop: 'point-drop',

/**
* Fired while dragging a point.
* @event point-drag
* @param {Object} detail.originalEvent object with details about the event sent
* @param {Object} point Point object where the event was sent from
*/
drag: 'point-drag',
};
}

Expand Down Expand Up @@ -1310,11 +1338,12 @@ class Chart extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement))) {
/** @private */
__createEventListeners(eventList, configuration, pathToAdd, eventType) {
const eventObject = this.__ensureObjectPath(configuration, pathToAdd);
const self = this;

for (let keys = Object.keys(eventList), i = 0; i < keys.length; i++) {
const key = keys[i];
if (!eventObject[key]) {
eventObject[key] = (event) => {
eventObject[key] = function (event) {
const customEvent = {
bubbles: false,
composed: true,
Expand All @@ -1324,6 +1353,12 @@ class Chart extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement))) {
},
};

if (key === 'dragStart') {
// for dragStart there is no information about point in the
// event object. However, 'this' references the point being dragged
customEvent.detail[eventType] = this;
}

if (event.type === 'afterSetExtremes') {
if (event.min == null || event.max == null) {
return;
Expand Down Expand Up @@ -1355,17 +1390,17 @@ class Chart extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement))) {
if (['beforePrint', 'beforeExport'].indexOf(event.type) >= 0) {
// Guard against another print 'before print' event coming before
// the 'after print' event.
if (!this.tempBodyStyle) {
if (!self.tempBodyStyle) {
let effectiveCss = '';

[...this.shadowRoot.querySelectorAll('style')].forEach((style) => {
[...self.shadowRoot.querySelectorAll('style')].forEach((style) => {
effectiveCss += style.textContent;
});

// Strip off host selectors that target individual instances
effectiveCss = effectiveCss.replace(/:host\(.+?\)/gu, (match) => {
const selector = match.substr(6, match.length - 7);
return this.matches(selector) ? '' : match;
return self.matches(selector) ? '' : match;
});

// Zoom out a bit to avoid clipping the chart's edge on paper
Expand All @@ -1376,29 +1411,29 @@ class Chart extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement))) {
` zoom: 90%;` + // Webkit
`}`;

this.tempBodyStyle = document.createElement('style');
this.tempBodyStyle.textContent = effectiveCss;
document.body.appendChild(this.tempBodyStyle);
if (this.options.chart.styledMode) {
self.tempBodyStyle = document.createElement('style');
self.tempBodyStyle.textContent = effectiveCss;
document.body.appendChild(self.tempBodyStyle);
if (self.options.chart.styledMode) {
document.body.setAttribute('styled-mode', '');
}
}
}

// Hook into afterPrint and afterExport to revert changes made before
if (['afterPrint', 'afterExport'].indexOf(event.type) >= 0) {
if (this.tempBodyStyle) {
document.body.removeChild(this.tempBodyStyle);
delete this.tempBodyStyle;
if (this.options.chart.styledMode) {
if (self.tempBodyStyle) {
document.body.removeChild(self.tempBodyStyle);
delete self.tempBodyStyle;
if (self.options.chart.styledMode) {
document.body.removeAttribute('styled-mode');
}
}
}

this.dispatchEvent(new CustomEvent(eventList[key], customEvent));
self.dispatchEvent(new CustomEvent(eventList[key], customEvent));

if (event.type === 'legendItemClick' && this._visibilityTogglingDisabled) {
if (event.type === 'legendItemClick' && self._visibilityTogglingDisabled) {
return false;
}
};
Expand Down
28 changes: 28 additions & 0 deletions packages/charts/test/events.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,34 @@ describe('vaadin-chart events', () => {
});
});

describe('draggable', () => {
beforeEach(async () => {
chart = fixtureSync(`
<vaadin-chart type="line" additional-options='{"plotOptions": {"series": {"dragDrop": {"draggableX": true}}}}'>
<vaadin-chart-series values="[10, 20]"></vaadin-chart-series>
</vaadin-chart>
`);
await oneEvent(chart, 'chart-load');
});

it('should emit dragStart when point clicked', () => {
const spy = sinon.spy();
chart.addEventListener('point-drag-start', spy);
chart.configuration.hoverPoint = chart.configuration.series[0].points[0];
chart.$.chart.querySelector('.highcharts-container').dispatchEvent(new MouseEvent('mousedown'));
expect(spy.calledOnce).to.be.true;
});

it('should resolve point object on dragStart', () => {
const spy = sinon.spy();
chart.addEventListener('point-drag-start', spy);
chart.configuration.hoverPoint = chart.configuration.series[0].points[0];
chart.$.chart.querySelector('.highcharts-container').dispatchEvent(new MouseEvent('mousedown'));
const event = spy.firstCall.args[0];
expect(event.detail.point).to.be.deep.equal(chart.configuration.series[0].points[0]);
});
});

describe('timeline', () => {
let chart;

Expand Down
21 changes: 21 additions & 0 deletions packages/charts/test/typings/chart.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import type {
ChartDrillupEvent,
ChartLoadEvent,
ChartPointClickEvent,
ChartPointDragEvent,
ChartPointDragStartEvent,
ChartPointDropEvent,
ChartPointLegendItemClickEvent,
ChartPointMouseOutEvent,
ChartPointMouseOverEvent,
Expand Down Expand Up @@ -206,6 +209,24 @@ chart.addEventListener('point-update', (event) => {
assertType<Point>(event.detail.originalEvent.target);
});

chart.addEventListener('point-drag-start', (event) => {
assertType<ChartPointDragStartEvent>(event);
assertType<Point>(event.detail.point);
assertType<Point>(event.detail.originalEvent.target);
});

chart.addEventListener('point-drop', (event) => {
assertType<ChartPointDropEvent>(event);
assertType<Point>(event.detail.point);
assertType<Point>(event.detail.originalEvent.target);
});

chart.addEventListener('point-drag', (event) => {
assertType<ChartPointDragEvent>(event);
assertType<Point>(event.detail.point);
assertType<Point>(event.detail.originalEvent.target);
});

chart.addEventListener('xaxes-extremes-set', (event) => {
assertType<ChartXaxesExtremesSetEvent>(event);
assertType<Axis>(event.detail.axis);
Expand Down