mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-06 16:26:52 +01:00
Make Chart.platform importable (#4509)
This commit is contained in:
@@ -8,7 +8,8 @@ Chart.helpers = require('./helpers/index');
|
||||
// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
|
||||
require('./core/core.helpers')(Chart);
|
||||
|
||||
require('./platforms/platform')(Chart);
|
||||
Chart.platform = require('./platforms/platform');
|
||||
|
||||
require('./core/core.element')(Chart);
|
||||
require('./core/core.plugin')(Chart);
|
||||
require('./core/core.animation')(Chart);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
var helpers = require('../helpers/index');
|
||||
var platform = require('../platforms/platform');
|
||||
|
||||
module.exports = function(Chart) {
|
||||
var plugins = Chart.plugins;
|
||||
var platform = Chart.platform;
|
||||
|
||||
// Create a dictionary of chart types, to allow for extension of existing types
|
||||
Chart.types = {};
|
||||
|
||||
@@ -1,342 +1,347 @@
|
||||
/**
|
||||
* Chart.Platform implementation for targeting a web browser
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var helpers = require('../helpers/index');
|
||||
|
||||
// Chart.Platform implementation for targeting a web browser
|
||||
module.exports = function() {
|
||||
/**
|
||||
* DOM event types -> Chart.js event types.
|
||||
* Note: only events with different types are mapped.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/Events
|
||||
*/
|
||||
|
||||
// DOM event types -> Chart.js event types.
|
||||
// Note: only events with different types are mapped.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Events
|
||||
var eventTypeMap = {
|
||||
// Touch events
|
||||
touchstart: 'mousedown',
|
||||
touchmove: 'mousemove',
|
||||
touchend: 'mouseup',
|
||||
var eventTypeMap = {
|
||||
// Touch events
|
||||
touchstart: 'mousedown',
|
||||
touchmove: 'mousemove',
|
||||
touchend: 'mouseup',
|
||||
|
||||
// Pointer events
|
||||
pointerenter: 'mouseenter',
|
||||
pointerdown: 'mousedown',
|
||||
pointermove: 'mousemove',
|
||||
pointerup: 'mouseup',
|
||||
pointerleave: 'mouseout',
|
||||
pointerout: 'mouseout'
|
||||
// Pointer events
|
||||
pointerenter: 'mouseenter',
|
||||
pointerdown: 'mousedown',
|
||||
pointermove: 'mousemove',
|
||||
pointerup: 'mouseup',
|
||||
pointerleave: 'mouseout',
|
||||
pointerout: 'mouseout'
|
||||
};
|
||||
|
||||
/**
|
||||
* The "used" size is the final value of a dimension property after all calculations have
|
||||
* been performed. This method uses the computed style of `element` but returns undefined
|
||||
* if the computed style is not expressed in pixels. That can happen in some cases where
|
||||
* `element` has a size relative to its parent and this last one is not yet displayed,
|
||||
* for example because of `display: none` on a parent node.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
|
||||
* @returns {Number} Size in pixels or undefined if unknown.
|
||||
*/
|
||||
function readUsedSize(element, property) {
|
||||
var value = helpers.getStyle(element, property);
|
||||
var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
|
||||
return matches? Number(matches[1]) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the canvas style and render size without modifying the canvas display size,
|
||||
* since responsiveness is handled by the controller.resize() method. The config is used
|
||||
* to determine the aspect ratio to apply in case no explicit height has been specified.
|
||||
*/
|
||||
function initCanvas(canvas, config) {
|
||||
var style = canvas.style;
|
||||
|
||||
// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
|
||||
// returns null or '' if no explicit value has been set to the canvas attribute.
|
||||
var renderHeight = canvas.getAttribute('height');
|
||||
var renderWidth = canvas.getAttribute('width');
|
||||
|
||||
// Chart.js modifies some canvas values that we want to restore on destroy
|
||||
canvas._chartjs = {
|
||||
initial: {
|
||||
height: renderHeight,
|
||||
width: renderWidth,
|
||||
style: {
|
||||
display: style.display,
|
||||
height: style.height,
|
||||
width: style.width
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The "used" size is the final value of a dimension property after all calculations have
|
||||
* been performed. This method uses the computed style of `element` but returns undefined
|
||||
* if the computed style is not expressed in pixels. That can happen in some cases where
|
||||
* `element` has a size relative to its parent and this last one is not yet displayed,
|
||||
* for example because of `display: none` on a parent node.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
|
||||
* @returns {Number} Size in pixels or undefined if unknown.
|
||||
*/
|
||||
function readUsedSize(element, property) {
|
||||
var value = helpers.getStyle(element, property);
|
||||
var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
|
||||
return matches? Number(matches[1]) : undefined;
|
||||
// Force canvas to display as block to avoid extra space caused by inline
|
||||
// elements, which would interfere with the responsive resize process.
|
||||
// https://github.com/chartjs/Chart.js/issues/2538
|
||||
style.display = style.display || 'block';
|
||||
|
||||
if (renderWidth === null || renderWidth === '') {
|
||||
var displayWidth = readUsedSize(canvas, 'width');
|
||||
if (displayWidth !== undefined) {
|
||||
canvas.width = displayWidth;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the canvas style and render size without modifying the canvas display size,
|
||||
* since responsiveness is handled by the controller.resize() method. The config is used
|
||||
* to determine the aspect ratio to apply in case no explicit height has been specified.
|
||||
*/
|
||||
function initCanvas(canvas, config) {
|
||||
var style = canvas.style;
|
||||
|
||||
// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
|
||||
// returns null or '' if no explicit value has been set to the canvas attribute.
|
||||
var renderHeight = canvas.getAttribute('height');
|
||||
var renderWidth = canvas.getAttribute('width');
|
||||
|
||||
// Chart.js modifies some canvas values that we want to restore on destroy
|
||||
canvas._chartjs = {
|
||||
initial: {
|
||||
height: renderHeight,
|
||||
width: renderWidth,
|
||||
style: {
|
||||
display: style.display,
|
||||
height: style.height,
|
||||
width: style.width
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Force canvas to display as block to avoid extra space caused by inline
|
||||
// elements, which would interfere with the responsive resize process.
|
||||
// https://github.com/chartjs/Chart.js/issues/2538
|
||||
style.display = style.display || 'block';
|
||||
|
||||
if (renderWidth === null || renderWidth === '') {
|
||||
var displayWidth = readUsedSize(canvas, 'width');
|
||||
if (renderHeight === null || renderHeight === '') {
|
||||
if (canvas.style.height === '') {
|
||||
// If no explicit render height and style height, let's apply the aspect ratio,
|
||||
// which one can be specified by the user but also by charts as default option
|
||||
// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
|
||||
canvas.height = canvas.width / (config.options.aspectRatio || 2);
|
||||
} else {
|
||||
var displayHeight = readUsedSize(canvas, 'height');
|
||||
if (displayWidth !== undefined) {
|
||||
canvas.width = displayWidth;
|
||||
canvas.height = displayHeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (renderHeight === null || renderHeight === '') {
|
||||
if (canvas.style.height === '') {
|
||||
// If no explicit render height and style height, let's apply the aspect ratio,
|
||||
// which one can be specified by the user but also by charts as default option
|
||||
// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
|
||||
canvas.height = canvas.width / (config.options.aspectRatio || 2);
|
||||
} else {
|
||||
var displayHeight = readUsedSize(canvas, 'height');
|
||||
if (displayWidth !== undefined) {
|
||||
canvas.height = displayHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects support for options object argument in addEventListener.
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
|
||||
* @private
|
||||
*/
|
||||
var supportsEventListenerOptions = (function() {
|
||||
var supports = false;
|
||||
try {
|
||||
var options = Object.defineProperty({}, 'passive', {
|
||||
get: function() {
|
||||
supports = true;
|
||||
return canvas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects support for options object argument in addEventListener.
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
|
||||
* @private
|
||||
*/
|
||||
var supportsEventListenerOptions = (function() {
|
||||
var supports = false;
|
||||
try {
|
||||
var options = Object.defineProperty({}, 'passive', {
|
||||
get: function() {
|
||||
supports = true;
|
||||
}
|
||||
});
|
||||
window.addEventListener('e', null, options);
|
||||
} catch (e) {
|
||||
// continue regardless of error
|
||||
}
|
||||
return supports;
|
||||
}());
|
||||
|
||||
// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
|
||||
// https://github.com/chartjs/Chart.js/issues/4287
|
||||
var eventListenerOptions = supportsEventListenerOptions? {passive: true} : false;
|
||||
|
||||
function addEventListener(node, type, listener) {
|
||||
node.addEventListener(type, listener, eventListenerOptions);
|
||||
}
|
||||
|
||||
function removeEventListener(node, type, listener) {
|
||||
node.removeEventListener(type, listener, eventListenerOptions);
|
||||
}
|
||||
|
||||
function createEvent(type, chart, x, y, nativeEvent) {
|
||||
return {
|
||||
type: type,
|
||||
chart: chart,
|
||||
native: nativeEvent || null,
|
||||
x: x !== undefined? x : null,
|
||||
y: y !== undefined? y : null,
|
||||
};
|
||||
}
|
||||
|
||||
function fromNativeEvent(event, chart) {
|
||||
var type = eventTypeMap[event.type] || event.type;
|
||||
var pos = helpers.getRelativePosition(event, chart);
|
||||
return createEvent(type, chart, pos.x, pos.y, event);
|
||||
}
|
||||
|
||||
function createResizer(handler) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.className = 'chartjs-hidden-iframe';
|
||||
iframe.style.cssText =
|
||||
'display:block;'+
|
||||
'overflow:hidden;'+
|
||||
'border:0;'+
|
||||
'margin:0;'+
|
||||
'top:0;'+
|
||||
'left:0;'+
|
||||
'bottom:0;'+
|
||||
'right:0;'+
|
||||
'height:100%;'+
|
||||
'width:100%;'+
|
||||
'position:absolute;'+
|
||||
'pointer-events:none;'+
|
||||
'z-index:-1;';
|
||||
|
||||
// Prevent the iframe to gain focus on tab.
|
||||
// https://github.com/chartjs/Chart.js/issues/3090
|
||||
iframe.tabIndex = -1;
|
||||
|
||||
// Prevent iframe from gaining focus on ItemMode keyboard navigation
|
||||
// Accessibility bug fix
|
||||
iframe.setAttribute('aria-hidden', 'true');
|
||||
|
||||
// If the iframe is re-attached to the DOM, the resize listener is removed because the
|
||||
// content is reloaded, so make sure to install the handler after the iframe is loaded.
|
||||
// https://github.com/chartjs/Chart.js/issues/3521
|
||||
addEventListener(iframe, 'load', function() {
|
||||
addEventListener(iframe.contentWindow || iframe, 'resize', handler);
|
||||
|
||||
// The iframe size might have changed while loading, which can also
|
||||
// happen if the size has been changed while detached from the DOM.
|
||||
handler();
|
||||
});
|
||||
|
||||
return iframe;
|
||||
}
|
||||
|
||||
function addResizeListener(node, listener, chart) {
|
||||
var stub = node._chartjs = {
|
||||
ticking: false
|
||||
};
|
||||
|
||||
// Throttle the callback notification until the next animation frame.
|
||||
var notify = function() {
|
||||
if (!stub.ticking) {
|
||||
stub.ticking = true;
|
||||
helpers.requestAnimFrame.call(window, function() {
|
||||
if (stub.resizer) {
|
||||
stub.ticking = false;
|
||||
return listener(createEvent('resize', chart));
|
||||
}
|
||||
});
|
||||
window.addEventListener('e', null, options);
|
||||
} catch (e) {
|
||||
// continue regardless of error
|
||||
}
|
||||
return supports;
|
||||
}());
|
||||
};
|
||||
|
||||
// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
|
||||
// https://github.com/chartjs/Chart.js/issues/4287
|
||||
var eventListenerOptions = supportsEventListenerOptions? {passive: true} : false;
|
||||
// Let's keep track of this added iframe and thus avoid DOM query when removing it.
|
||||
stub.resizer = createResizer(notify);
|
||||
|
||||
function addEventListener(node, type, listener) {
|
||||
node.addEventListener(type, listener, eventListenerOptions);
|
||||
node.insertBefore(stub.resizer, node.firstChild);
|
||||
}
|
||||
|
||||
function removeResizeListener(node) {
|
||||
if (!node || !node._chartjs) {
|
||||
return;
|
||||
}
|
||||
|
||||
function removeEventListener(node, type, listener) {
|
||||
node.removeEventListener(type, listener, eventListenerOptions);
|
||||
var resizer = node._chartjs.resizer;
|
||||
if (resizer) {
|
||||
resizer.parentNode.removeChild(resizer);
|
||||
node._chartjs.resizer = null;
|
||||
}
|
||||
|
||||
function createEvent(type, chart, x, y, nativeEvent) {
|
||||
return {
|
||||
type: type,
|
||||
chart: chart,
|
||||
native: nativeEvent || null,
|
||||
x: x !== undefined? x : null,
|
||||
y: y !== undefined? y : null,
|
||||
};
|
||||
}
|
||||
delete node._chartjs;
|
||||
}
|
||||
|
||||
function fromNativeEvent(event, chart) {
|
||||
var type = eventTypeMap[event.type] || event.type;
|
||||
var pos = helpers.getRelativePosition(event, chart);
|
||||
return createEvent(type, chart, pos.x, pos.y, event);
|
||||
}
|
||||
module.exports = {
|
||||
acquireContext: function(item, config) {
|
||||
if (typeof item === 'string') {
|
||||
item = document.getElementById(item);
|
||||
} else if (item.length) {
|
||||
// Support for array based queries (such as jQuery)
|
||||
item = item[0];
|
||||
}
|
||||
|
||||
function createResizer(handler) {
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.className = 'chartjs-hidden-iframe';
|
||||
iframe.style.cssText =
|
||||
'display:block;'+
|
||||
'overflow:hidden;'+
|
||||
'border:0;'+
|
||||
'margin:0;'+
|
||||
'top:0;'+
|
||||
'left:0;'+
|
||||
'bottom:0;'+
|
||||
'right:0;'+
|
||||
'height:100%;'+
|
||||
'width:100%;'+
|
||||
'position:absolute;'+
|
||||
'pointer-events:none;'+
|
||||
'z-index:-1;';
|
||||
if (item && item.canvas) {
|
||||
// Support for any object associated to a canvas (including a context2d)
|
||||
item = item.canvas;
|
||||
}
|
||||
|
||||
// Prevent the iframe to gain focus on tab.
|
||||
// https://github.com/chartjs/Chart.js/issues/3090
|
||||
iframe.tabIndex = -1;
|
||||
// To prevent canvas fingerprinting, some add-ons undefine the getContext
|
||||
// method, for example: https://github.com/kkapsner/CanvasBlocker
|
||||
// https://github.com/chartjs/Chart.js/issues/2807
|
||||
var context = item && item.getContext && item.getContext('2d');
|
||||
|
||||
// Prevent iframe from gaining focus on ItemMode keyboard navigation
|
||||
// Accessibility bug fix
|
||||
iframe.setAttribute('aria-hidden', 'true');
|
||||
// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
|
||||
// inside an iframe or when running in a protected environment. We could guess the
|
||||
// types from their toString() value but let's keep things flexible and assume it's
|
||||
// a sufficient condition if the item has a context2D which has item as `canvas`.
|
||||
// https://github.com/chartjs/Chart.js/issues/3887
|
||||
// https://github.com/chartjs/Chart.js/issues/4102
|
||||
// https://github.com/chartjs/Chart.js/issues/4152
|
||||
if (context && context.canvas === item) {
|
||||
initCanvas(item, config);
|
||||
return context;
|
||||
}
|
||||
|
||||
// If the iframe is re-attached to the DOM, the resize listener is removed because the
|
||||
// content is reloaded, so make sure to install the handler after the iframe is loaded.
|
||||
// https://github.com/chartjs/Chart.js/issues/3521
|
||||
addEventListener(iframe, 'load', function() {
|
||||
addEventListener(iframe.contentWindow || iframe, 'resize', handler);
|
||||
return null;
|
||||
},
|
||||
|
||||
// The iframe size might have changed while loading, which can also
|
||||
// happen if the size has been changed while detached from the DOM.
|
||||
handler();
|
||||
});
|
||||
|
||||
return iframe;
|
||||
}
|
||||
|
||||
function addResizeListener(node, listener, chart) {
|
||||
var stub = node._chartjs = {
|
||||
ticking: false
|
||||
};
|
||||
|
||||
// Throttle the callback notification until the next animation frame.
|
||||
var notify = function() {
|
||||
if (!stub.ticking) {
|
||||
stub.ticking = true;
|
||||
helpers.requestAnimFrame.call(window, function() {
|
||||
if (stub.resizer) {
|
||||
stub.ticking = false;
|
||||
return listener(createEvent('resize', chart));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Let's keep track of this added iframe and thus avoid DOM query when removing it.
|
||||
stub.resizer = createResizer(notify);
|
||||
|
||||
node.insertBefore(stub.resizer, node.firstChild);
|
||||
}
|
||||
|
||||
function removeResizeListener(node) {
|
||||
if (!node || !node._chartjs) {
|
||||
releaseContext: function(context) {
|
||||
var canvas = context.canvas;
|
||||
if (!canvas._chartjs) {
|
||||
return;
|
||||
}
|
||||
|
||||
var resizer = node._chartjs.resizer;
|
||||
if (resizer) {
|
||||
resizer.parentNode.removeChild(resizer);
|
||||
node._chartjs.resizer = null;
|
||||
var initial = canvas._chartjs.initial;
|
||||
['height', 'width'].forEach(function(prop) {
|
||||
var value = initial[prop];
|
||||
if (helpers.isNullOrUndef(value)) {
|
||||
canvas.removeAttribute(prop);
|
||||
} else {
|
||||
canvas.setAttribute(prop, value);
|
||||
}
|
||||
});
|
||||
|
||||
helpers.each(initial.style || {}, function(value, key) {
|
||||
canvas.style[key] = value;
|
||||
});
|
||||
|
||||
// The canvas render size might have been changed (and thus the state stack discarded),
|
||||
// we can't use save() and restore() to restore the initial state. So make sure that at
|
||||
// least the canvas context is reset to the default state by setting the canvas width.
|
||||
// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
|
||||
canvas.width = canvas.width;
|
||||
|
||||
delete canvas._chartjs;
|
||||
},
|
||||
|
||||
addEventListener: function(chart, type, listener) {
|
||||
var canvas = chart.canvas;
|
||||
if (type === 'resize') {
|
||||
// Note: the resize event is not supported on all browsers.
|
||||
addResizeListener(canvas.parentNode, listener, chart);
|
||||
return;
|
||||
}
|
||||
|
||||
delete node._chartjs;
|
||||
var stub = listener._chartjs || (listener._chartjs = {});
|
||||
var proxies = stub.proxies || (stub.proxies = {});
|
||||
var proxy = proxies[chart.id + '_' + type] = function(event) {
|
||||
listener(fromNativeEvent(event, chart));
|
||||
};
|
||||
|
||||
addEventListener(canvas, type, proxy);
|
||||
},
|
||||
|
||||
removeEventListener: function(chart, type, listener) {
|
||||
var canvas = chart.canvas;
|
||||
if (type === 'resize') {
|
||||
// Note: the resize event is not supported on all browsers.
|
||||
removeResizeListener(canvas.parentNode, listener);
|
||||
return;
|
||||
}
|
||||
|
||||
var stub = listener._chartjs || {};
|
||||
var proxies = stub.proxies || {};
|
||||
var proxy = proxies[chart.id + '_' + type];
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeEventListener(canvas, type, proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use EventTarget.addEventListener instead.
|
||||
* EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
|
||||
* @function Chart.helpers.addEvent
|
||||
* @deprecated since version 2.7.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
helpers.addEvent = addEventListener;
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use EventTarget.removeEventListener instead.
|
||||
* EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
|
||||
* @function Chart.helpers.removeEvent
|
||||
* @deprecated since version 2.7.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
helpers.removeEvent = removeEventListener;
|
||||
|
||||
return {
|
||||
acquireContext: function(item, config) {
|
||||
if (typeof item === 'string') {
|
||||
item = document.getElementById(item);
|
||||
} else if (item.length) {
|
||||
// Support for array based queries (such as jQuery)
|
||||
item = item[0];
|
||||
}
|
||||
|
||||
if (item && item.canvas) {
|
||||
// Support for any object associated to a canvas (including a context2d)
|
||||
item = item.canvas;
|
||||
}
|
||||
|
||||
// To prevent canvas fingerprinting, some add-ons undefine the getContext
|
||||
// method, for example: https://github.com/kkapsner/CanvasBlocker
|
||||
// https://github.com/chartjs/Chart.js/issues/2807
|
||||
var context = item && item.getContext && item.getContext('2d');
|
||||
|
||||
// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
|
||||
// inside an iframe or when running in a protected environment. We could guess the
|
||||
// types from their toString() value but let's keep things flexible and assume it's
|
||||
// a sufficient condition if the item has a context2D which has item as `canvas`.
|
||||
// https://github.com/chartjs/Chart.js/issues/3887
|
||||
// https://github.com/chartjs/Chart.js/issues/4102
|
||||
// https://github.com/chartjs/Chart.js/issues/4152
|
||||
if (context && context.canvas === item) {
|
||||
initCanvas(item, config);
|
||||
return context;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
releaseContext: function(context) {
|
||||
var canvas = context.canvas;
|
||||
if (!canvas._chartjs) {
|
||||
return;
|
||||
}
|
||||
|
||||
var initial = canvas._chartjs.initial;
|
||||
['height', 'width'].forEach(function(prop) {
|
||||
var value = initial[prop];
|
||||
if (helpers.isNullOrUndef(value)) {
|
||||
canvas.removeAttribute(prop);
|
||||
} else {
|
||||
canvas.setAttribute(prop, value);
|
||||
}
|
||||
});
|
||||
|
||||
helpers.each(initial.style || {}, function(value, key) {
|
||||
canvas.style[key] = value;
|
||||
});
|
||||
|
||||
// The canvas render size might have been changed (and thus the state stack discarded),
|
||||
// we can't use save() and restore() to restore the initial state. So make sure that at
|
||||
// least the canvas context is reset to the default state by setting the canvas width.
|
||||
// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
|
||||
canvas.width = canvas.width;
|
||||
|
||||
delete canvas._chartjs;
|
||||
},
|
||||
|
||||
addEventListener: function(chart, type, listener) {
|
||||
var canvas = chart.canvas;
|
||||
if (type === 'resize') {
|
||||
// Note: the resize event is not supported on all browsers.
|
||||
addResizeListener(canvas.parentNode, listener, chart);
|
||||
return;
|
||||
}
|
||||
|
||||
var stub = listener._chartjs || (listener._chartjs = {});
|
||||
var proxies = stub.proxies || (stub.proxies = {});
|
||||
var proxy = proxies[chart.id + '_' + type] = function(event) {
|
||||
listener(fromNativeEvent(event, chart));
|
||||
};
|
||||
|
||||
addEventListener(canvas, type, proxy);
|
||||
},
|
||||
|
||||
removeEventListener: function(chart, type, listener) {
|
||||
var canvas = chart.canvas;
|
||||
if (type === 'resize') {
|
||||
// Note: the resize event is not supported on all browsers.
|
||||
removeResizeListener(canvas.parentNode, listener);
|
||||
return;
|
||||
}
|
||||
|
||||
var stub = listener._chartjs || {};
|
||||
var proxies = stub.proxies || {};
|
||||
var proxy = proxies[chart.id + '_' + type];
|
||||
if (!proxy) {
|
||||
return;
|
||||
}
|
||||
|
||||
removeEventListener(canvas, type, proxy);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// DEPRECATIONS
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use EventTarget.addEventListener instead.
|
||||
* EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
|
||||
* @function Chart.helpers.addEvent
|
||||
* @deprecated since version 2.7.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
helpers.addEvent = addEventListener;
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, use EventTarget.removeEventListener instead.
|
||||
* EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
|
||||
* @function Chart.helpers.removeEvent
|
||||
* @deprecated since version 2.7.0
|
||||
* @todo remove at version 3
|
||||
* @private
|
||||
*/
|
||||
helpers.removeEvent = removeEventListener;
|
||||
|
||||
@@ -6,66 +6,63 @@ var helpers = require('../helpers/index');
|
||||
// @TODO Make possible to select another platform at build time.
|
||||
var implementation = require('./platform.dom');
|
||||
|
||||
module.exports = function(Chart) {
|
||||
/**
|
||||
* @namespace Chart.platform
|
||||
* @see https://chartjs.gitbooks.io/proposals/content/Platform.html
|
||||
* @since 2.4.0
|
||||
*/
|
||||
module.exports = helpers.extend({
|
||||
/**
|
||||
* @namespace Chart.platform
|
||||
* @see https://chartjs.gitbooks.io/proposals/content/Platform.html
|
||||
* @since 2.4.0
|
||||
* Called at chart construction time, returns a context2d instance implementing
|
||||
* the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
|
||||
* @param {*} item - The native item from which to acquire context (platform specific)
|
||||
* @param {Object} options - The chart options
|
||||
* @returns {CanvasRenderingContext2D} context2d instance
|
||||
*/
|
||||
Chart.platform = {
|
||||
/**
|
||||
* Called at chart construction time, returns a context2d instance implementing
|
||||
* the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
|
||||
* @param {*} item - The native item from which to acquire context (platform specific)
|
||||
* @param {Object} options - The chart options
|
||||
* @returns {CanvasRenderingContext2D} context2d instance
|
||||
*/
|
||||
acquireContext: function() {},
|
||||
|
||||
/**
|
||||
* Called at chart destruction time, releases any resources associated to the context
|
||||
* previously returned by the acquireContext() method.
|
||||
* @param {CanvasRenderingContext2D} context - The context2d instance
|
||||
* @returns {Boolean} true if the method succeeded, else false
|
||||
*/
|
||||
releaseContext: function() {},
|
||||
|
||||
/**
|
||||
* Registers the specified listener on the given chart.
|
||||
* @param {Chart} chart - Chart from which to listen for event
|
||||
* @param {String} type - The ({@link IEvent}) type to listen for
|
||||
* @param {Function} listener - Receives a notification (an object that implements
|
||||
* the {@link IEvent} interface) when an event of the specified type occurs.
|
||||
*/
|
||||
addEventListener: function() {},
|
||||
|
||||
/**
|
||||
* Removes the specified listener previously registered with addEventListener.
|
||||
* @param {Chart} chart -Chart from which to remove the listener
|
||||
* @param {String} type - The ({@link IEvent}) type to remove
|
||||
* @param {Function} listener - The listener function to remove from the event target.
|
||||
*/
|
||||
removeEventListener: function() {}
|
||||
};
|
||||
acquireContext: function() {},
|
||||
|
||||
/**
|
||||
* @interface IPlatform
|
||||
* Allows abstracting platform dependencies away from the chart
|
||||
* @borrows Chart.platform.acquireContext as acquireContext
|
||||
* @borrows Chart.platform.releaseContext as releaseContext
|
||||
* @borrows Chart.platform.addEventListener as addEventListener
|
||||
* @borrows Chart.platform.removeEventListener as removeEventListener
|
||||
* Called at chart destruction time, releases any resources associated to the context
|
||||
* previously returned by the acquireContext() method.
|
||||
* @param {CanvasRenderingContext2D} context - The context2d instance
|
||||
* @returns {Boolean} true if the method succeeded, else false
|
||||
*/
|
||||
releaseContext: function() {},
|
||||
|
||||
/**
|
||||
* @interface IEvent
|
||||
* @prop {String} type - The event type name, possible values are:
|
||||
* 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
|
||||
* 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
|
||||
* @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
|
||||
* @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
|
||||
* @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
|
||||
* Registers the specified listener on the given chart.
|
||||
* @param {Chart} chart - Chart from which to listen for event
|
||||
* @param {String} type - The ({@link IEvent}) type to listen for
|
||||
* @param {Function} listener - Receives a notification (an object that implements
|
||||
* the {@link IEvent} interface) when an event of the specified type occurs.
|
||||
*/
|
||||
addEventListener: function() {},
|
||||
|
||||
helpers.extend(Chart.platform, implementation(Chart));
|
||||
};
|
||||
/**
|
||||
* Removes the specified listener previously registered with addEventListener.
|
||||
* @param {Chart} chart -Chart from which to remove the listener
|
||||
* @param {String} type - The ({@link IEvent}) type to remove
|
||||
* @param {Function} listener - The listener function to remove from the event target.
|
||||
*/
|
||||
removeEventListener: function() {}
|
||||
|
||||
}, implementation);
|
||||
|
||||
/**
|
||||
* @interface IPlatform
|
||||
* Allows abstracting platform dependencies away from the chart
|
||||
* @borrows Chart.platform.acquireContext as acquireContext
|
||||
* @borrows Chart.platform.releaseContext as releaseContext
|
||||
* @borrows Chart.platform.addEventListener as addEventListener
|
||||
* @borrows Chart.platform.removeEventListener as removeEventListener
|
||||
*/
|
||||
|
||||
/**
|
||||
* @interface IEvent
|
||||
* @prop {String} type - The event type name, possible values are:
|
||||
* 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
|
||||
* 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
|
||||
* @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
|
||||
* @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
|
||||
* @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user