]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Use hidden iframe to detect resize + obey max width when getting maximum size. Update...
authorEvert Timberg <evert.timberg@gmail.com>
Sun, 20 Sep 2015 14:30:12 +0000 (10:30 -0400)
committerEvert Timberg <evert.timberg@gmail.com>
Sun, 20 Sep 2015 14:30:12 +0000 (10:30 -0400)
samples/bar.html
src/core/core.controller.js
src/core/core.helpers.js
src/core/core.js

index eb8796ac5cb4d1e1f8760eeccbe0f78d0de5f39b..7f1d8e7eabfe73959dd60cb968d0282dd8f2701d 100644 (file)
@@ -5,10 +5,15 @@
     <title>Bar Chart</title>
     <script src="../node_modules/jquery/dist/jquery.min.js"></script>
     <script src="../Chart.js"></script>
+    <style type="text/css">
+        canvas {
+            border: 1px solid red;
+        }
+    </style>
 </head>
 
 <body>
-    <div style="width: 50%">
+    <div id="container" style="width: 50%; height: 25%; display:none;">
         <canvas id="canvas" height="450" width="600"></canvas>
     </div>
     <button id="randomizeData">Randomize Data</button>
@@ -16,6 +21,7 @@
     <button id="removeDataset">Remove Dataset</button>
     <button id="addData">Add Data</button>
     <button id="removeData">Remove Data</button>
+    <button id="show">Show</button>
     <div>
         <h3>Legend</h3>
         <div id="legendContainer">
             data: barChartData,
             options: {
                 responsive: true,
+                scales: {
+                    xAxes: [{
+                        // So that bars fill the entire width of the grid
+                        categorySpacing: 0,
+                        spacing: 0
+                    }]
+                }
             }
         });
 
 
     $('#addData').click(function() {
         if (barChartData.datasets.length > 0) {
-            barChartData.labels.push('dataset #' + barChartData.labels.length);
+            barChartData.labels.push('data #' + barChartData.labels.length);
 
             for (var index = 0; index < barChartData.datasets.length; ++index) {
                 window.myBar.addData(randomScalingFactor(), index);
         });
         updateLegend();
     });
+
+    $('#show').click(function() {
+        document.getElementById('container').style.display = '';
+    });
     </script>
 </body>
 
index 806248485a98372f5716752c76553c0975011a40..614b0579ddb4a2b9e859465c1df85f4a471842c8 100644 (file)
 
                resize: function resize(silent) {
                        this.stop();
-                       var canvas = this.chart.canvas,
-                               newWidth = helpers.getMaximumWidth(this.chart.canvas),
-                               newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : helpers.getMaximumHeight(this.chart.canvas);
+                       var canvas = this.chart.canvas;
+                       var newWidth = helpers.getMaximumWidth(this.chart.canvas);
+                       var newHeight = (this.options.maintainAspectRatio && isNaN(this.chart.aspectRatio) === false && isFinite(this.chart.aspectRatio) && this.chart.aspectRatio !== 0) 
+                               ? newWidth / this.chart.aspectRatio 
+                               : helpers.getMaximumHeight(this.chart.canvas);
 
                        canvas.width = this.chart.width = newWidth;
                        canvas.height = this.chart.height = newHeight;
                destroy: function destroy() {
                        this.clear();
                        helpers.unbindEvents(this, this.events);
-                       var canvas = this.chart.canvas;
+                       helpers.removeResizeListener(this.chart.canvas.parentNode);
 
-                       // Reset canvas height/width attributes starts a fresh with the canvas context
+                       // Reset canvas height/width attributes
+                       var canvas = this.chart.canvas;
                        canvas.width = this.chart.width;
                        canvas.height = this.chart.height;
 
-                       // < IE9 doesn't support removeProperty
-                       if (canvas.style.removeProperty) {
-                               canvas.style.removeProperty('width');
-                               canvas.style.removeProperty('height');
-                       } else {
-                               canvas.style.removeAttribute('width');
-                               canvas.style.removeAttribute('height');
+                       // if we scaled the canvas in response to a devicePixelRatio !== 1, we need to undo that transform here
+                       if (this.chart.originalDevicePixelRatio !== undefined) {
+                               canvas.scale(1 / this.chart.originalDevicePixelRatio, 1 / this.chart.originalDevicePixelRatio);
                        }
 
                        delete Chart.instances[this.id];
index ab58b0789dc7b1bb7567447402318da639292370..b81bf96093efb32a8743c732d086dcb04cc42d6b 100644 (file)
                                removeEvent(chartInstance.chart.canvas, eventName, handler);
                        });
                },
+               getConstraintWidth = helpers.getConstraintWidth = function(domNode) { // returns Number or undefined if no constraint
+                       var constrainedWidth;
+                       var constrainedWNode = document.defaultView.getComputedStyle(domNode)['max-width'];
+                       var constrainedWContainer = document.defaultView.getComputedStyle(domNode.parentNode)['max-width'];
+                       var hasCWNode = constrainedWNode !== null && constrainedWNode !== "none";
+                       var hasCWContainer = constrainedWContainer !== null && constrainedWContainer !== "none";
+
+                       if (hasCWNode || hasCWContainer) {
+                               constrainedWidth = Math.min((hasCWNode ? parseInt(constrainedWNode, 10) : Number.POSITIVE_INFINITY), (hasCWContainer ? parseInt(constrainedWContainer, 10) : Number.POSITIVE_INFINITY));
+                       }
+                       return constrainedWidth;
+               },
+               getConstraintHeight = helpers.getConstraintHeight = function(domNode) { // returns Number or undefined if no constraint
+
+                       var constrainedHeight;
+                       var constrainedHNode = document.defaultView.getComputedStyle(domNode)['max-height'];
+                       var constrainedHContainer = document.defaultView.getComputedStyle(domNode.parentNode)['max-height'];
+                       var hasCHNode = constrainedHNode !== null && constrainedHNode !== "none";
+                       var hasCHContainer = constrainedHContainer !== null && constrainedHContainer !== "none";
+
+                       if (constrainedHNode || constrainedHContainer) {
+                               constrainedHeight = Math.min((hasCHNode ? parseInt(constrainedHNode, 10) : Number.POSITIVE_INFINITY), (hasCHContainer ? parseInt(constrainedHContainer, 10) : Number.POSITIVE_INFINITY));
+                       }
+                       return constrainedHeight;
+               },
                getMaximumWidth = helpers.getMaximumWidth = function(domNode) {
-                       var container = domNode.parentNode,
-                               padding = parseInt(getStyle(container, 'padding-left')) + parseInt(getStyle(container, 'padding-right'));
-                       // TODO = check cross browser stuff with this.
-                       return container.clientWidth - padding;
+                       var container = domNode.parentNode;
+                       var padding = parseInt(getStyle(container, 'padding-left')) + parseInt(getStyle(container, 'padding-right'));
+                       
+                       var w = container.clientWidth - padding;
+                       var cw = getConstraintWidth(domNode);
+                       if (cw !== undefined) {
+                               w = Math.min(w, cw);
+                       }
+
+                       return w;
                },
                getMaximumHeight = helpers.getMaximumHeight = function(domNode) {
-                       var container = domNode.parentNode,
-                               padding = parseInt(getStyle(container, 'padding-bottom')) + parseInt(getStyle(container, 'padding-top'));
-                       // TODO = check cross browser stuff with this.
-                       return container.clientHeight - padding;
+                       var container = domNode.parentNode;
+                       var padding = parseInt(getStyle(container, 'padding-top')) + parseInt(getStyle(container, 'padding-bottom'));
+                       
+                       var h = container.clientHeight - padding;
+                       var ch = getConstraintHeight(domNode);
+                       if (ch !== undefined) {
+                               h = Math.min(h, ch);
+                       }
+
+                       return h;
                },
                getStyle = helpers.getStyle = function(el, property) {
                        return el.currentStyle ?
                },
                getMaximumSize = helpers.getMaximumSize = helpers.getMaximumWidth, // legacy support
                retinaScale = helpers.retinaScale = function(chart) {
-                       var ctx = chart.ctx,
-                               width = chart.canvas.width,
-                               height = chart.canvas.height;
+                       var ctx = chart.ctx;
+                       var width = chart.canvas.width;
+                       var height = chart.canvas.height;
 
-                       if (window.devicePixelRatio) {
-                               ctx.canvas.style.width = width + "px";
-                               ctx.canvas.style.height = height + "px";
+                       if (window.devicePixelRatio !== 1) {
                                ctx.canvas.height = height * window.devicePixelRatio;
                                ctx.canvas.width = width * window.devicePixelRatio;
                                ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
+
+                               // Store the device pixel ratio so that we can go backwards in `destroy`.
+                               // The devicePixelRatio changes with zoom, so there are no guarantees that it is the same
+                               // when destroy is called
+                               chart.originalDevicePixelRatio = chart.originalDevicePixelRatio || window.devicePixelRatio;
                        }
                },
                //-- Canvas methods
                        }
                        return window.Color(color);
                },
+               addResizeListener = helpers.addResizeListener = function(node, callback) {
+                       // Hide an iframe before the node
+                       var hiddenIframe = document.createElement('iframe');
+                       var hiddenIframeClass = 'chartjs-hidden-iframe';
+
+                       if (hiddenIframe.classlist) {
+                               // can use classlist
+                               hiddenIframe.classlist.add(hiddenIframeClass);
+                       } else {
+                               hiddenIframe.setAttribute('class', hiddenIframeClass)
+                       }
+
+                       // Set the style
+                       hiddenIframe.style.width = '100%';
+                       hiddenIframe.style.display = 'block';
+                       hiddenIframe.style.border = 0;
+                       hiddenIframe.style.height = 0;
+                       hiddenIframe.style.margin = 0;
+                       hiddenIframe.style.position = 'absolute';
+                       hiddenIframe.style.left = 0;
+                       hiddenIframe.style.right = 0;
+                       hiddenIframe.style.top = 0;
+                       hiddenIframe.style.bottom = 0;
+
+                       // Insert the iframe so that contentWindow is available
+                       node.insertBefore(hiddenIframe, node.firstChild);
+
+                       var timer = 0;
+                       (hiddenIframe.contentWindow || hiddenIframe).onresize = function() {
+                               if (callback) {
+                                       callback();
+                               }
+                       }
+               },
+               removeResizeListener = helpers.removeResizeListener = function(node) {
+                       var hiddenIframe = node.querySelector('.chartjs-hidden-iframe');
+
+                       // Remove the resize detect iframe
+                       if (hiddenIframe) {
+                               hiddenIframe.remove();
+                       }
+               },
                isArray = helpers.isArray = function(obj) {
                        if (!Array.isArray) {
                                return Object.prototype.toString.call(arg) === '[object Array]';
index 42c214e1444a59b8acf1234aab20adfa92552132..512b4f42e5ed9dff0770e8871ecbd4cb8d75328e 100755 (executable)
@@ -19,7 +19,6 @@
 
        //Occupy the global variable of Chart, and create a simple base class
        var Chart = function(context, config) {
-               var chart = this;
                this.config = config;
 
                // Support a jQuery'd canvas element
                        context = context.getContext("2d");
                }
 
+               this.ctx = context;
                this.canvas = context.canvas;
 
-               this.ctx = context;
+               // Figure out what the size of the chart will be.
+               // If the canvas has a specified width and height, we use those else
+               // we look to see if the canvas node has a CSS width and height. 
+               // If there is still no height, fill the parent container
+               this.width = context.canvas.width || parseInt(Chart.helpers.getStyle(context.canvas, 'width')) || Chart.helpers.getMaximumWidth(context.canvas);
+               this.height = context.canvas.height || parseInt(Chart.helpers.getStyle(context.canvas, 'height')) || Chart.helpers.getMaximumHeight(context.canvas);
 
-               //Variables global to the chart
-               var computeDimension = function(element, dimension) {
-                       if (element['offset' + dimension]) {
-                               return element['offset' + dimension];
-                       } else {
-                               return document.defaultView.getComputedStyle(element).getPropertyValue(dimension);
-                       }
-               };
-
-               var width = this.width = computeDimension(context.canvas, 'Width') || context.canvas.width;
-               var height = this.height = computeDimension(context.canvas, 'Height') || context.canvas.height;
+               this.aspectRatio = this.width / this.height;
 
-               // Firefox requires this to work correctly
-               context.canvas.width = width;
-               context.canvas.height = height;
+               if (isNaN(this.aspectRatio) || isFinite(this.aspectRatio) === false) {
+                       // If the canvas has no size, try and figure out what the aspect ratio will be.
+                       // Some charts prefer square canvases (pie, radar, etc). If that is specified, use that
+                       // else use the canvas default ratio of 2
+                       this.aspectRatio = config.aspectRatio !== undefined ? config.aspectRatio : 2;
+               }
 
-               width = this.width = context.canvas.width;
-               height = this.height = context.canvas.height;
-               this.aspectRatio = this.width / this.height;
-               //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
+               // High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
                Chart.helpers.retinaScale(this);
 
+               // Always bind this so that if the responsive state changes we still work
+               var _this = this;
+               Chart.helpers.addResizeListener(context.canvas.parentNode, function() {
+                       if (config.options.responsive) {
+                               _this.controller.resize();
+                       }
+               });
+
                if (config) {
                        this.controller = new Chart.Controller(this);
                        return this.controller;