From: Jukka Kurkela Date: Sat, 16 Jan 2021 19:06:27 +0000 (+0200) Subject: Disable Path2D caching when chart is animated (#8319) X-Git-Tag: v3.0.0-beta.9~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea34e8b81476e9cc1ef4b916fa2cfadf2a803edf;p=thirdparty%2FChart.js.git Disable Path2D caching when chart is animated (#8319) * Disable Path2D caching when chart is animated * Add note to performance docs --- diff --git a/docs/docs/general/performance.md b/docs/docs/general/performance.md index 25dfaadc8..51cde5c05 100644 --- a/docs/docs/general/performance.md +++ b/docs/docs/general/performance.md @@ -35,6 +35,7 @@ Set the [`ticks.sampleSize`](./axes/cartesian/index.mdx#tick-configuration) opti ## Disable Animations If your charts have long render times, it is a good idea to disable animations. Doing so will mean that the chart needs to only be rendered once during an update instead of multiple times. This will have the effect of reducing CPU usage and improving general page performance. +Line charts use Path2D caching when animations are disabled. To disable animations diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index 16edd7cb3..3690fa90d 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -29,9 +29,13 @@ export default class LineController extends DatasetController { // Update Line line.points = points; + // In resize mode only point locations change, so no need to set the options. if (mode !== 'resize') { - me.updateElement(line, undefined, {options: me.resolveDatasetElementOptions()}, mode); + me.updateElement(line, undefined, { + animated: !animationsDisabled, + options: me.resolveDatasetElementOptions() + }, mode); } // Update Points diff --git a/src/elements/element.line.js b/src/elements/element.line.js index 5d0a27632..9379bae53 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -3,7 +3,6 @@ import {_bezierInterpolation, _pointInLine, _steppedInterpolation} from '../help import {_computeSegments, _boundSegments} from '../helpers/helpers.segment'; import {_steppedLineTo, _bezierCurveTo} from '../helpers/helpers.canvas'; import {_updateBezierControlPoints} from '../helpers/helpers.curve'; -import {_coordsAnimated} from '../helpers/helpers.extras'; /** * @typedef { import("./element.point").default } PointElement @@ -204,6 +203,7 @@ export default class LineElement extends Element { constructor(cfg) { super(); + this.animated = true; this.options = undefined; this._loop = undefined; this._fullLoop = undefined; @@ -351,8 +351,9 @@ export default class LineElement extends Element { * @param {number} [count] */ draw(ctx, chartArea, start, count) { - const options = this.options || {}; - const points = this.points || []; + const me = this; + const options = me.options || {}; + const points = me.points || []; if (!points.length || !options.borderWidth) { return; @@ -362,10 +363,10 @@ export default class LineElement extends Element { setStyle(ctx, options); - let path = this._path; + let path = me._path; if (!path) { - path = this._path = new Path2D(); - if (this.path(path, start, count)) { + path = me._path = new Path2D(); + if (me.path(path, start, count)) { path.closePath(); } } @@ -374,12 +375,10 @@ export default class LineElement extends Element { ctx.restore(); - if (_coordsAnimated(points[0]) || _coordsAnimated(points[points.length - 1])) { - // When point coordinates are animating, we need to recalculate the - // path (and control points when beziers are used). Only coordinates - // matter, other animations are ignored. - this._pointsUpdated = false; - this._path = undefined; + if (me.animated) { + // When line is animated, the control points and path are not cached. + me._pointsUpdated = false; + me._path = undefined; } } } diff --git a/src/helpers/helpers.extras.js b/src/helpers/helpers.extras.js index b140cdd7f..280ad832b 100644 --- a/src/helpers/helpers.extras.js +++ b/src/helpers/helpers.extras.js @@ -56,14 +56,3 @@ export const _toLeftRightCenter = (align) => align === 'start' ? 'left' : align * @private */ export const _alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2; - -/** - * Return true if `x` or `y` property (coordinates) of the element is currently animated. - * @param {object} element - * @returns {boolean} - * @private - */ -export function _coordsAnimated(element) { - const anims = element && element.$animations; - return anims && ((anims.x && anims.x.active()) || (anims.y && anims.y.active())); -} diff --git a/test/specs/element.line.tests.js b/test/specs/element.line.tests.js index 2299de219..e29d5c44f 100644 --- a/test/specs/element.line.tests.js +++ b/test/specs/element.line.tests.js @@ -10,4 +10,26 @@ describe('Chart.elements.LineElement', function() { expect(line).not.toBe(undefined); expect(line.points).toEqual([1, 2, 3, 4]); }); + + it('should not cache path when animations are enabled', function(done) { + var chart = window.acquireChart({ + type: 'line', + data: { + datasets: [{ + data: [0, -1, 0], + label: 'dataset1', + }], + labels: ['label1', 'label2', 'label3'] + }, + options: { + animation: { + duration: 50, + onComplete: () => { + expect(chart.getDatasetMeta(0).dataset._path).toBeUndefined(); + done(); + } + } + } + }); + }); });