/
utils.js
184 lines (160 loc) · 5.29 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import {spritingOn, spritingOff} from './spriting';
export function createCanvas(w, h) {
var canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
return canvas;
}
export function readImageData(url, callback) {
var image = new Image();
image.onload = function() {
var h = image.height;
var w = image.width;
var canvas = createCanvas(w, h);
var ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0, w, h);
callback(ctx.getImageData(0, 0, w, h));
};
image.src = url;
}
/**
* Injects a new canvas (and div wrapper) and creates the associated Chart instance
* using the given config. Additional options allow tweaking elements generation.
* @param {object} [config] - Chart config.
* @param {object} [options] - Chart acquisition options.
* @param {object} [options.canvas] - Canvas attributes.
* @param {object} [options.wrapper] - Canvas wrapper attributes.
* @param {boolean} [options.useOffscreenCanvas] - use an OffscreenCanvas instead of the normal HTMLCanvasElement.
* @param {boolean} [options.useShadowDOM] - use shadowDom
* @param {boolean} [options.persistent] - If true, the chart will not be released after the spec.
*/
export function _acquireChart(config, options) {
var wrapper = document.createElement('div');
var canvas = document.createElement('canvas');
var chart, key;
config = config || {};
options = options || {};
options.canvas = options.canvas || {height: 512, width: 512};
options.wrapper = options.wrapper || {class: 'chartjs-wrapper'};
for (key in options.canvas) {
if (Object.prototype.hasOwnProperty.call(options.canvas, key)) {
canvas.setAttribute(key, options.canvas[key]);
}
}
for (key in options.wrapper) {
if (Object.prototype.hasOwnProperty.call(options.wrapper, key)) {
wrapper.setAttribute(key, options.wrapper[key]);
}
}
// by default, remove chart animation and auto resize
config.options = config.options || {};
config.options.animation = config.options.animation === undefined ? false : config.options.animation;
config.options.responsive = config.options.responsive === undefined ? false : config.options.responsive;
config.options.locale = config.options.locale || 'en-US';
if (options.useShadowDOM) {
if (!wrapper.attachShadow) {
// If shadowDOM is not supported by the browsers, mark test as 'pending'.
return pending();
}
wrapper.attachShadow({mode: 'open'}).appendChild(canvas);
} else {
wrapper.appendChild(canvas);
}
window.document.body.appendChild(wrapper);
try {
var ctx;
if (options.useOffscreenCanvas) {
if (!canvas.transferControlToOffscreen) {
// If this browser does not support offscreen canvas, mark the test as 'pending', which will skip the
// test.
// TODO: switch to skip() once it's implemented (https://github.com/jasmine/jasmine/issues/1709), or
// remove if all browsers implement `transferControlToOffscreen`
return pending();
}
var offscreenCanvas = canvas.transferControlToOffscreen();
ctx = offscreenCanvas.getContext('2d');
} else {
ctx = canvas.getContext('2d');
}
if (options.spriteText) {
spritingOn(ctx);
}
chart = new Chart(ctx, config);
} catch (e) {
window.document.body.removeChild(wrapper);
throw e;
}
chart.$test = {
persistent: options.persistent,
wrapper: wrapper
};
return chart;
}
export function _releaseChart(chart) {
spritingOff(chart.ctx);
chart.destroy();
var wrapper = (chart.$test || {}).wrapper;
if (wrapper && wrapper.parentNode) {
wrapper.parentNode.removeChild(wrapper);
}
}
export function injectCSS(css) {
// https://stackoverflow.com/q/3922139
var head = document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.setAttribute('type', 'text/css');
if (style.styleSheet) { // IE
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
}
export function waitForResize(chart, callback) {
var override = chart.resize;
chart.resize = function() {
chart.resize = override;
override.apply(this, arguments);
callback();
};
}
export function afterEvent(chart, type, callback) {
var override = chart._eventHandler;
chart._eventHandler = function(event) {
override.call(this, event);
if (event.type === type || (event.native && event.native.type === type)) {
chart._eventHandler = override;
// eslint-disable-next-line callback-return
callback();
}
};
}
function _resolveElementPoint(el) {
var point = {x: 0, y: 0};
if (el) {
if (typeof el.getCenterPoint === 'function') {
point = el.getCenterPoint();
} else if (el.x !== undefined && el.y !== undefined) {
point = el;
}
}
return point;
}
export async function triggerMouseEvent(chart, type, el) {
var node = chart.canvas;
var rect = node.getBoundingClientRect();
var point = _resolveElementPoint(el);
var event = new MouseEvent(type, {
clientX: rect.left + point.x,
clientY: rect.top + point.y,
cancelable: true,
bubbles: true,
view: window
});
var promise = new Promise((resolve) => {
afterEvent(chart, type, resolve);
});
node.dispatchEvent(event);
await promise;
return event;
}