<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>
<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>
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];
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]';
//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;