Skip to content

Enable initial animation on annotations #755

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

Merged
merged 51 commits into from
Feb 26, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
28fa957
Enable initial animation on annotations
stockiNail Jun 1, 2022
172eb5b
fixes some CC issues
stockiNail Jun 1, 2022
2e357e1
apply review 1
stockiNail Jun 1, 2022
980f3b6
adds fixtures
stockiNail Jun 1, 2022
91c3ab7
adds test cases with callback
stockiNail Jun 1, 2022
56e0f55
improves code on default application and drawPoint function
stockiNail Jun 1, 2022
05aa1b5
adds test case on callback which returns undef
stockiNail Jun 1, 2022
2247bc1
adds animation spec to test that the annotation is really animating
stockiNail Jun 3, 2022
9910062
adds types
stockiNail Jun 3, 2022
92dfb51
adds doc
stockiNail Jun 3, 2022
781a2f6
adds samples
stockiNail Jun 3, 2022
6ca8aec
fixes and improves test case on init animation
stockiNail Jun 3, 2022
983f197
fixes lint
stockiNail Jun 3, 2022
3e70704
fixes multiple access to cart config in test case
stockiNail Jun 3, 2022
962ee4b
Add element diagrams to the annotation types guide
stockiNail Jun 6, 2022
05e619c
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jun 8, 2022
22a3aa3
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jun 8, 2022
f5186fe
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jun 8, 2022
22251c3
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Jun 9, 2022
6d87201
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jul 21, 2022
84366b3
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jul 22, 2022
ec3a554
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jul 26, 2022
1324e43
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Aug 4, 2022
693e84d
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Aug 19, 2022
cc3fb5a
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Aug 19, 2022
30b5941
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Aug 19, 2022
b30c95e
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Sep 28, 2022
ff2a323
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Sep 28, 2022
8ac1896
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Sep 28, 2022
8aea0ad
apply review
stockiNail Sep 28, 2022
b686c7a
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Oct 28, 2022
30446eb
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Nov 15, 2022
63e01f8
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Nov 15, 2022
235712c
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Nov 17, 2022
5114654
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jan 9, 2023
0672d27
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Jan 9, 2023
e43a62e
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jan 27, 2023
5069380
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Jan 27, 2023
7f2e747
changes initAnimation options name to init
stockiNail Jan 27, 2023
76294b6
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Jan 30, 2023
f9835e1
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Feb 4, 2023
dfcef02
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Feb 4, 2023
f8cc9c6
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Feb 6, 2023
b4fd4ec
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Feb 6, 2023
65c55ec
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Feb 24, 2023
67f2425
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Feb 24, 2023
c552b5a
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Feb 25, 2023
07463fa
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Feb 25, 2023
e079753
Merge remote-tracking branch 'origin/master' into initAnimation
stockiNail Feb 25, 2023
8034582
Merge branch 'master' of https://github.com/chartjs/chartjs-plugin-an…
stockiNail Feb 25, 2023
b2f1faf
rebased
stockiNail Feb 25, 2023
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
17 changes: 11 additions & 6 deletions src/elements.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function updateElements(chart, state, options, mode) {
properties.skip = toSkip(properties);

if ('elements' in properties) {
updateSubElements(element, properties, resolver, animations);
updateSubElements(element, properties.elements, resolver, animations);
// Remove the sub-element definitions from properties, so the actual elements
// are not overwritten by their definitions
delete properties.elements;
Expand All @@ -61,6 +61,7 @@ export function updateElements(chart, state, options, mode) {
Object.assign(element, properties);
}

applyInitProperties(element, properties.initProperties);
properties.options = resolveAnnotationOptions(resolver);

animations.update(element, properties);
Expand All @@ -78,13 +79,13 @@ function resolveAnimations(chart, animOpts, mode) {
return new Animations(chart, animOpts);
}

function updateSubElements(mainElement, {elements, initProperties}, resolver, animations) {
function updateSubElements(mainElement, elements, resolver, animations) {
const subElements = mainElement.elements || (mainElement.elements = []);
subElements.length = elements.length;
for (let i = 0; i < elements.length; i++) {
const definition = elements[i];
const properties = definition.properties;
const subElement = getOrCreateElement(subElements, i, definition.type, initProperties);
const subElement = getOrCreateElement(subElements, i, definition.type, definition.initProperties);
const subResolver = resolver[definition.optionScope].override(definition);
properties.options = resolveAnnotationOptions(subResolver);
animations.update(subElement, properties);
Expand All @@ -96,9 +97,7 @@ function getOrCreateElement(elements, index, type, initProperties) {
let element = elements[index];
if (!element || !(element instanceof elementClass)) {
element = elements[index] = new elementClass();
if (isObject(initProperties)) {
Object.assign(element, initProperties);
}
applyInitProperties(element, initProperties);
}
return element;
}
Expand Down Expand Up @@ -148,3 +147,9 @@ function resyncElements(elements, annotations) {
}
return elements;
}

function applyInitProperties(element, initProperties) {
if (isObject(initProperties)) {
Object.assign(element, initProperties);
}
}
4 changes: 2 additions & 2 deletions src/helpers/helpers.canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,10 @@ export function drawLabel(ctx, rect, options) {
ctx.textBaseline = 'middle';
ctx.textAlign = options.textAlign;
if (setTextStrokeStyle(ctx, options)) {
labels.forEach((l, i) => ctx.strokeText(l, x, y + (i * lh)));
labels.forEach((l, i) => ctx.strokeText(l, x, y + (i * lh), rect.width));
}
ctx.fillStyle = options.color;
labels.forEach((l, i) => ctx.fillText(l, x, y + (i * lh)));
labels.forEach((l, i) => ctx.fillText(l, x, y + (i * lh), rect.width));
ctx.restore();
}

Expand Down
2 changes: 2 additions & 0 deletions src/helpers/helpers.chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export function resolvePointProperties(chart, options) {
y2: box.y + size + options.yAdjust,
centerX: box.centerX + options.xAdjust,
centerY: box.centerY + options.yAdjust,
radius,
width: size,
height: size
};
Expand All @@ -154,6 +155,7 @@ function getChartCircle(chart, options) {
y2: point.y + options.radius + options.yAdjust,
centerX: point.x + options.xAdjust,
centerY: point.y + options.yAdjust,
radius: options.radius,
width: size,
height: size
};
Expand Down
71 changes: 71 additions & 0 deletions src/helpers/helpers.options.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
import {isObject, valueOrDefault, defined} from 'chart.js/helpers';
import {clamp} from './helpers.core';

const animationModes = {
fade: (area, {centerX, centerY}) => ({x: centerX, y: centerY, x2: centerX, y2: centerY, width: 0, height: 0}),
left: () => ({x: 0, x2: 0}),
top: () => ({y: 0, y2: 0}),
right: (area) => ({x: area.right, x2: area.right}),
bottom: (area) => ({y: area.bottom, y2: area.bottom}),
topLeft: () => ({x: 0, x2: 0, y: 0, y2: 0}),
topRight: (area) => ({x: area.right, x2: area.right, y: 0, y2: 0}),
bottomLeft: (area) => ({x: 0, x2: 0, y: area.bottom, y2: area.bottom}),
bottomRight: (area) => ({x: area.right, x2: area.right, y: area.bottom, y2: area.bottom}),
};

const pointAnimationModes = {
fade: (area, {centerX, centerY}) => ({centerX, centerY, radius: 0, width: 0, height: 0}),
left: () => ({centerX: 0}),
top: () => ({centerY: 0}),
right: (area) => ({centerX: area.right}),
bottom: (area) => ({centerY: area.bottom}),
topLeft: () => ({centerX: 0, centerY: 0}),
topRight: (area) => ({centerX: area.right, centerY: 0}),
bottomLeft: (area) => ({centerX: 0, centerY: area.bottom}),
bottomRight: (area) => ({centerX: area.right, centerY: area.bottom}),
};

const isPercentString = (s) => typeof s === 'string' && s.endsWith('%');
const toPercent = (s) => clamp(parseFloat(s) / 100, 0, 1);

/**
* @typedef { import("chart.js").Chart } Chart
* @typedef { import('../../types/element').AnnotationBoxModel } AnnotationBoxModel
* @typedef { import('../../types/options').AnnotationPointCoordinates } AnnotationPointCoordinates
* @typedef { import('../../types/label').CoreLabelOptions } CoreLabelOptions
* @typedef { import('../../types/label').LabelPositionObject } LabelPositionObject
Expand Down Expand Up @@ -85,3 +111,48 @@ export function toPosition(value) {
export function isBoundToPoint(options) {
return options && (defined(options.xValue) || defined(options.yValue));
}

/**
* @param {Chart} chart
* @param {AnnotationBoxModel} properties
* @param {CoreAnnotationOptions} options
* @param {{centerBased: boolean, useRadius: boolean}} [animOpts={centerBased: false, useRadius: false}]
* @returns {AnnotationBoxModel}
*/
export function initAnimationProperties(chart, properties, options, animOpts = {centerBased: false, useRadius: false}) {
if (!options.initAnimation) {
return;
}
const {centerBased, useRadius} = animOpts;
const {mode, fade} = toAnimationMode(options.initAnimation);
const modes = centerBased ? pointAnimationModes : animationModes;
const modeImpl = modes[mode];
if (modeImpl) {
const animProps = modeImpl(chart.chartArea, properties);
applyFading(animProps, fade, useRadius);
return animProps;
}
}

function toAnimationMode(value) {
if (isObject(value)) {
return {
mode: value.mode,
fade: value.fade === true,
};
}
return {
mode: value
};
}

function applyFading(properties, fade, useRadius) {
if (fade) {
if (useRadius) {
properties.radius = 0;
} else {
properties.width = 0;
properties.height = 0;
}
}
}
9 changes: 5 additions & 4 deletions src/types/box.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Element} from 'chart.js';
import {toPadding, toRadians} from 'chart.js/helpers';
import {drawBox, getRelativePosition, measureLabelSize, resolveBoxProperties, toPosition, inBoxRange, rotated, translate, getElementCenterPoint} from '../helpers';
import {drawBox, getRelativePosition, measureLabelSize, resolveBoxProperties, toPosition, inBoxRange, rotated, translate, getElementCenterPoint, initAnimationProperties} from '../helpers';

export default class BoxAnnotation extends Element {

Expand Down Expand Up @@ -40,13 +40,13 @@ export default class BoxAnnotation extends Element {

resolveElementProperties(chart, options) {
const properties = resolveBoxProperties(chart, options);
const {x, y} = properties;
properties.initProperties = initAnimationProperties(chart, properties, options);
properties.elements = [{
type: 'label',
optionScope: 'label',
properties: resolveLabelElementProperties(chart, properties, options)
properties: resolveLabelElementProperties(chart, properties, options),
initProperties: properties.initProperties
}];
properties.initProperties = {x, y};
return properties;
}
}
Expand All @@ -64,6 +64,7 @@ BoxAnnotation.defaults = {
borderShadowColor: 'transparent',
borderWidth: 1,
display: true,
initAnimation: undefined,
label: {
backgroundColor: 'transparent',
borderWidth: 0,
Expand Down
8 changes: 5 additions & 3 deletions src/types/ellipse.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Element} from 'chart.js';
import {PI, toRadians} from 'chart.js/helpers';
import {EPSILON, resolveBoxProperties, setBorderStyle, setShadowStyle, rotated, translate, getElementCenterPoint} from '../helpers';
import {EPSILON, resolveBoxProperties, setBorderStyle, setShadowStyle, rotated, translate, getElementCenterPoint, initAnimationProperties} from '../helpers';

export default class EllipseAnnotation extends Element {

Expand All @@ -23,7 +23,6 @@ export default class EllipseAnnotation extends Element {

draw(ctx) {
const {width, height, centerX, centerY, options} = this;

ctx.save();
translate(ctx, this.getCenterPoint(), options.rotation);
setShadowStyle(ctx, this.options);
Expand All @@ -40,7 +39,9 @@ export default class EllipseAnnotation extends Element {
}

resolveElementProperties(chart, options) {
return resolveBoxProperties(chart, options);
const properties = resolveBoxProperties(chart, options);
properties.initProperties = initAnimationProperties(chart, properties, options, {centerBased: true});
return properties;
}

}
Expand All @@ -55,6 +56,7 @@ EllipseAnnotation.defaults = {
borderShadowColor: 'transparent',
borderWidth: 1,
display: true,
initAnimation: undefined,
rotation: 0,
shadowBlur: 0,
shadowOffsetX: 0,
Expand Down
4 changes: 3 additions & 1 deletion src/types/label.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Element} from 'chart.js';
import {drawBox, drawLabel, measureLabelSize, getChartPoint, toPosition, setBorderStyle, getSize, inBoxRange, isBoundToPoint, resolveBoxProperties, getRelativePosition, translate, rotated, getElementCenterPoint} from '../helpers';
import {drawBox, drawLabel, measureLabelSize, getChartPoint, toPosition, setBorderStyle, getSize, inBoxRange, isBoundToPoint, resolveBoxProperties, getRelativePosition, translate, rotated, getElementCenterPoint, initAnimationProperties} from '../helpers';
import {toPadding, toRadians, distanceBetweenPoints} from 'chart.js/helpers';

const positions = ['left', 'bottom', 'top', 'right'];
Expand Down Expand Up @@ -46,6 +46,7 @@ export default class LabelAnnotation extends Element {
const labelSize = measureLabelSize(chart.ctx, options);
const boxSize = measureRect(point, labelSize, options, padding);
return {
initProperties: initAnimationProperties(chart, boxSize, options),
pointX: point.x,
pointY: point.y,
...boxSize,
Expand Down Expand Up @@ -91,6 +92,7 @@ LabelAnnotation.defaults = {
weight: undefined
},
height: undefined,
initAnimation: undefined,
padding: 6,
position: 'center',
rotation: 0,
Expand Down
7 changes: 5 additions & 2 deletions src/types/line.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Element} from 'chart.js';
import {PI, toRadians, toDegrees, toPadding} from 'chart.js/helpers';
import {EPSILON, clamp, scaleValue, measureLabelSize, getRelativePosition, setBorderStyle, setShadowStyle, getElementCenterPoint, retrieveScaleID, getDimensionByScale} from '../helpers';
import {EPSILON, clamp, scaleValue, measureLabelSize, getRelativePosition, setBorderStyle, setShadowStyle, getElementCenterPoint, retrieveScaleID, getDimensionByScale, initAnimationProperties} from '../helpers';

const pointInLine = (p1, p2, t) => ({x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y)});
const interpolateX = (y, p1, p2) => pointInLine(p1, p2, Math.abs((y - p1.y) / (p2.y - p1.y))).x;
Expand Down Expand Up @@ -92,10 +92,12 @@ export default class LineAnnotation extends Element {
if (!inside) {
options.label.display = false;
}
properties.initProperties = initAnimationProperties(chart, properties, options);
properties.elements = [{
type: 'label',
optionScope: 'label',
properties: resolveLabelElementProperties(chart, properties, options.label)
properties: resolveLabelElementProperties(chart, properties, options.label),
initProperties: properties.initProperties
}];
return properties;
}
Expand Down Expand Up @@ -136,6 +138,7 @@ LineAnnotation.defaults = {
borderWidth: 2,
display: true,
endValue: undefined,
initAnimation: undefined,
label: {
backgroundColor: 'rgba(0,0,0,0.8)',
backgroundShadowColor: 'transparent',
Expand Down
10 changes: 8 additions & 2 deletions src/types/point.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Element} from 'chart.js';
import {drawPoint} from 'chart.js/helpers';
import {inPointRange, getElementCenterPoint, resolvePointProperties, setBorderStyle, setShadowStyle, isImageOrCanvas} from '../helpers';
import {inPointRange, getElementCenterPoint, resolvePointProperties, setBorderStyle, setShadowStyle, isImageOrCanvas, initAnimationProperties} from '../helpers';

export default class PointAnnotation extends Element {

Expand Down Expand Up @@ -29,7 +29,10 @@ export default class PointAnnotation extends Element {
ctx.fillStyle = options.backgroundColor;
setShadowStyle(ctx, options);
const stroke = setBorderStyle(ctx, options);
// REMINDER: Sets to 0 in order to avoid that Chart.js function will perform stroking
options.borderWidth = 0;
// for animation on radius, the element property must be used
options.radius = this.radius;
drawPoint(ctx, options, this.centerX, this.centerY);
if (stroke && !isImageOrCanvas(options.pointStyle)) {
ctx.shadowColor = options.borderShadowColor;
Expand All @@ -40,7 +43,9 @@ export default class PointAnnotation extends Element {
}

resolveElementProperties(chart, options) {
return resolvePointProperties(chart, options);
const properties = resolvePointProperties(chart, options);
properties.initProperties = initAnimationProperties(chart, properties, options, {centerBased: true, useRadius: true});
return properties;
}
}

Expand All @@ -54,6 +59,7 @@ PointAnnotation.defaults = {
borderShadowColor: 'transparent',
borderWidth: 1,
display: true,
initAnimation: undefined,
pointStyle: 'circle',
radius: 10,
rotation: 0,
Expand Down
9 changes: 5 additions & 4 deletions src/types/polygon.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Element} from 'chart.js';
import {PI, RAD_PER_DEG, toRadians} from 'chart.js/helpers';
import {setBorderStyle, resolvePointProperties, getElementCenterPoint, setShadowStyle, rotated} from '../helpers';
import {setBorderStyle, resolvePointProperties, getElementCenterPoint, setShadowStyle, rotated, initAnimationProperties} from '../helpers';

export default class PolygonAnnotation extends Element {

Expand Down Expand Up @@ -47,16 +47,16 @@ export default class PolygonAnnotation extends Element {

resolveElementProperties(chart, options) {
const properties = resolvePointProperties(chart, options);
const {x, y} = properties;
const {sides, rotation} = options;
const elements = [];
const angle = (2 * PI) / sides;
let rad = rotation * RAD_PER_DEG;
for (let i = 0; i < sides; i++, rad += angle) {
elements.push(buildPointElement(properties, options, rad));
const elProps = buildPointElement(properties, options, rad);
elProps.initProperties = initAnimationProperties(chart, properties, options);
elements.push(elProps);
}
properties.elements = elements;
properties.initProperties = {x, y};
return properties;
}
}
Expand All @@ -73,6 +73,7 @@ PolygonAnnotation.defaults = {
borderShadowColor: 'transparent',
borderWidth: 1,
display: true,
initAnimation: 'fade',
point: {
radius: 0
},
Expand Down