]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Make `Chart.platform` importable (#4509)
authorSimon Brunel <simonbrunel@users.noreply.github.com>
Sun, 16 Jul 2017 09:02:25 +0000 (11:02 +0200)
committerGitHub <noreply@github.com>
Sun, 16 Jul 2017 09:02:25 +0000 (11:02 +0200)
src/chart.js
src/core/core.controller.js
src/platforms/platform.dom.js
src/platforms/platform.js

index 493568686902e0a43d656f26ea271968df5b7e53..9580c2387b5c3de42e8d9fe4f223efd0ff6b169e 100644 (file)
@@ -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);
index c8578a9373791927f3fba82c5dbec0fc82285370..4a86d70d2fbbb9e53ada26e1f4832e1980a5e3a3 100644 (file)
@@ -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 = {};
index f8e328954bce471eab7f8e102640674d109bb0f4..d0895ae9674de584c8a387667362cc59ccdf4a20 100644 (file)
+/**
+ * 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.
-       // https://developer.mozilla.org/en-US/docs/Web/Events
-       var eventTypeMap = {
-               // Touch events
-               touchstart: 'mousedown',
-               touchmove: 'mousemove',
-               touchend: 'mouseup',
-
-               // 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;
-       }
+/**
+ * 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
+ */
+
+var eventTypeMap = {
+       // Touch events
+       touchstart: 'mousedown',
+       touchmove: 'mousemove',
+       touchend: 'mouseup',
+
+       // Pointer events
+       pointerenter: 'mouseenter',
+       pointerdown: 'mousedown',
+       pointermove: 'mousemove',
+       pointerup: 'mouseup',
+       pointerleave: 'mouseout',
+       pointerout: 'mouseout'
+};
 
-       /**
-        * 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;
+}
+
+/**
+ * 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';
+       // 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;
-                       }
+       if (renderWidth === null || renderWidth === '') {
+               var displayWidth = readUsedSize(canvas, 'width');
+               if (displayWidth !== undefined) {
+                       canvas.width = displayWidth;
                }
+       }
 
-               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;
-                               }
+       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;
-                               }
-                       });
-                       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);
+       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;
+}());
 
-       function removeEventListener(node, type, listener) {
-               node.removeEventListener(type, listener, eventListenerOptions);
-       }
+// 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 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 addEventListener(node, type, listener) {
+       node.addEventListener(type, listener, eventListenerOptions);
+}
 
-       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 removeEventListener(node, type, listener) {
+       node.removeEventListener(type, listener, eventListenerOptions);
+}
 
-       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();
-               });
+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
+       };
 
-               return iframe;
-       }
+       // 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));
+                               }
+                       });
+               }
+       };
 
-       function addResizeListener(node, listener, chart) {
-               var stub = node._chartjs = {
-                       ticking: false
-               };
+       // Let's keep track of this added iframe and thus avoid DOM query when removing it.
+       stub.resizer = createResizer(notify);
 
-               // 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));
-                                       }
-                               });
-                       }
-               };
+       node.insertBefore(stub.resizer, node.firstChild);
+}
 
-               // Let's keep track of this added iframe and thus avoid DOM query when removing it.
-               stub.resizer = createResizer(notify);
+function removeResizeListener(node) {
+       if (!node || !node._chartjs) {
+               return;
+       }
 
-               node.insertBefore(stub.resizer, node.firstChild);
+       var resizer = node._chartjs.resizer;
+       if (resizer) {
+               resizer.parentNode.removeChild(resizer);
+               node._chartjs.resizer = null;
        }
 
-       function removeResizeListener(node) {
-               if (!node || !node._chartjs) {
-                       return;
+       delete node._chartjs;
+}
+
+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];
                }
 
-               var resizer = node._chartjs.resizer;
-               if (resizer) {
-                       resizer.parentNode.removeChild(resizer);
-                       node._chartjs.resizer = null;
+               if (item && item.canvas) {
+                       // Support for any object associated to a canvas (including a context2d)
+                       item = item.canvas;
                }
 
-               delete node._chartjs;
-       }
+               // 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;
+               }
 
-       /**
-        * 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 null;
+       },
 
-       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];
-                       }
+       releaseContext: function(context) {
+               var canvas = context.canvas;
+               if (!canvas._chartjs) {
+                       return;
+               }
 
-                       if (item && item.canvas) {
-                               // Support for any object associated to a canvas (including a context2d)
-                               item = item.canvas;
+               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);
                        }
+               });
 
-                       // 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;
-                       }
+               helpers.each(initial.style || {}, function(value, key) {
+                       canvas.style[key] = value;
+               });
 
-                       return null;
-               },
+               // 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;
 
-               releaseContext: function(context) {
-                       var canvas = context.canvas;
-                       if (!canvas._chartjs) {
-                               return;
-                       }
+               delete canvas._chartjs;
+       },
 
-                       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;
-                       });
+       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;
+               }
 
-                       // 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));
+               };
 
-                       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;
-                       }
+               addEventListener(canvas, type, proxy);
+       },
 
-                       var stub = listener._chartjs || {};
-                       var proxies = stub.proxies || {};
-                       var proxy = proxies[chart.id + '_' + type];
-                       if (!proxy) {
-                               return;
-                       }
+       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;
+               }
 
-                       removeEventListener(canvas, type, proxy);
+               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;
index 3464d5ff59c42949aa8f5075d0a4d1700a00e089..199e9548dbf8e008c142868d2b81d6e2e4ca3231 100644 (file)
@@ -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() {},
+       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() {}
-       };
+       /**
+        * 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 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
+        * 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() {},
 
        /**
-        * @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)
+        * 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
+ */
 
-       helpers.extend(Chart.platform, implementation(Chart));
-};
+/**
+ * @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)
+ */