Skip to content

Commit b4ad90d

Browse files
authored
Add custom scriptable context (#366)
* Add custom scriptable context * Typo
1 parent be2a76c commit b4ad90d

File tree

4 files changed

+87
-25
lines changed

4 files changed

+87
-25
lines changed

docs/guide/options.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ Fonts use the same format as [chart.js](https://www.chartjs.org/docs/master/gene
1010

1111
## Scriptable Options
1212

13-
As with most options in chart.js, the annotation plugin options are scriptable. This means that a function can be passed which returns the value as needed. In the example below, the annotation is hidden when the screen is less than 1000px wide
13+
As with most options in chart.js, the annotation plugin options are scriptable. This means that a function can be passed which returns the value as needed. In the example below, the annotation is hidden when the screen is less than 1000px wide.
14+
The function receives 2 arguments, first is the [option context](#option-context) representing contextual information. An options resolver is passed as second argumet, which can be used to access other option in the same context.
1415

1516
```js chart-editor
1617
/* <block:options:0> */
@@ -71,3 +72,31 @@ The `drawTime` option for an annotation determines where in the chart lifecycle
7172
| `'beforeDatasetsDraw'` | Occurs after drawing of axes, but before datasets
7273
| `'afterDatasetsDraw'` | Occurs after drawing of datasets but before items such as the tooltip
7374
| `'afterDraw'` | After other drawing is completed.
75+
76+
## Option Context
77+
78+
The option context is used to give contextual information when resolving options and only applies to scriptable options. The object is preserved, so it can be used to store and pass information between calls / options.
79+
80+
There are 2 levels of option context objects:
81+
82+
* `chart`
83+
* `annotation`
84+
85+
The context object contains the following properties:
86+
87+
### chart
88+
89+
* `chart`: the associated chart
90+
* `type`: `'chart'`
91+
92+
The [chart](#chart) option context is provided by Chart.js. It is passed to scriptable options when resolving annotation `id`, `type` and `drawTime` or adjusting scale ranges in `afterDataLimits` hook. The options resolved at that time are `scaleID`, `xScaleID`, `yScaleID`, `value`, `endValue`, `xMin`, `xMax`, `yMin`, `yMax`, `xValue` and `yValue`.
93+
94+
### annotation
95+
96+
In addition to [chart](#chart)
97+
98+
* `id`: the annotation id
99+
* `element`: the annotation element
100+
* `type`: `'annotation'`
101+
102+
The [annotation](#annotation) option context is passed to scriptable options in all other cases, except when resolving `id`, `type` or adjusting scale ranges. The same values resolved in `afterDataLimits` with [chart](#chart) context are again evaluated in `afterUpdate` with [annotation](#annotation) context.

src/annotation.js

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Animations, Chart, defaults} from 'chart.js';
2-
import {clipArea, unclipArea, isFinite, valueOrDefault, isObject} from 'chart.js/helpers';
2+
import {clipArea, unclipArea, isFinite, valueOrDefault, isObject, isArray} from 'chart.js/helpers';
33
import {handleEvent, hooks, updateListeners} from './events';
44
import BoxAnnotation from './types/box';
55
import LineAnnotation from './types/line';
@@ -48,19 +48,15 @@ export default {
4848

4949
let annotationOptions = options.annotations;
5050
if (isObject(annotationOptions)) {
51-
const array = new Array();
5251
Object.keys(annotationOptions).forEach(key => {
5352
const value = annotationOptions[key];
5453
if (isObject(value)) {
5554
value.id = key;
56-
array.push(value);
55+
annotations.push(value);
5756
}
5857
});
59-
annotationOptions = array;
60-
}
61-
62-
for (const annotation of annotationOptions) {
63-
annotations.push(resolveAnnotationOptions(annotation));
58+
} else if (isArray(annotationOptions)) {
59+
annotations.push(...annotationOptions);
6460
}
6561
},
6662

@@ -134,20 +130,6 @@ const directUpdater = {
134130
update: Object.assign
135131
};
136132

137-
138-
function resolveAnnotationOptions(resolver) {
139-
const elType = annotationTypes[resolver.type] || annotationTypes.line;
140-
const result = {};
141-
for (const name of optionNames(elType)) {
142-
result[name] = resolver[name];
143-
}
144-
return result;
145-
}
146-
147-
function optionNames(type) {
148-
return ['id', 'type', 'drawTime'].concat(Object.keys(type.defaults), Object.keys(type.defaultRoutes), hooks);
149-
}
150-
151133
function resolveAnimations(chart, animOpts, mode) {
152134
if (mode === 'reset' || mode === 'none' || mode === 'resize') {
153135
return directUpdater;
@@ -168,12 +150,21 @@ function updateElements(chart, state, options, mode) {
168150
if (!el || !(el instanceof elType)) {
169151
el = elements[i] = new elType();
170152
}
171-
const properties = el.resolveElementProperties(chart, annotation);
172-
properties.options = annotation;
153+
const opts = annotation.setContext(getContext(chart, el, annotation));
154+
const properties = el.resolveElementProperties(chart, opts);
155+
properties.options = opts;
173156
animations.update(el, properties);
174157
}
175158
}
176159

160+
function getContext(chart, element, annotation) {
161+
return element.$context || (element.$context = Object.assign(Object.create(chart.getContext()), {
162+
element,
163+
id: annotation.id,
164+
type: 'annotation'
165+
}));
166+
}
167+
177168
function resyncElements(elements, annotations) {
178169
const count = annotations.length;
179170
const start = elements.length;

test/fixtures/line/axis-index.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
module.exports = {
2+
config: {
3+
type: 'line',
4+
data: {
5+
datasets: [{
6+
data: [10, 20, 30, 0, 55],
7+
}],
8+
labels: ['A', 'B', 'C', 'D', 'E']
9+
},
10+
options: {
11+
plugins: {
12+
legend: false,
13+
annotation: {
14+
annotations: {
15+
annotation1: {
16+
type: 'line',
17+
scaleID: 'y',
18+
borderWidth: 3,
19+
borderColor: 'black',
20+
value: (ctx) => {
21+
if (ctx.type === 'annotation') {
22+
const scale = ctx.chart.scales.y;
23+
if (scale.ticks && scale.ticks.length > 1) {
24+
return scale.ticks[1].value;
25+
}
26+
}
27+
return 0;
28+
},
29+
}
30+
}
31+
}
32+
},
33+
}
34+
},
35+
options: {
36+
spriteText: true,
37+
run(chart) {
38+
chart.hide(0);
39+
chart.show(0);
40+
}
41+
}
42+
};

test/fixtures/line/axis-index.png

21.3 KB
Loading

0 commit comments

Comments
 (0)