Skip to content

Commit

Permalink
Merge pull request #1467 from etimberg/feature/resize_problems
Browse files Browse the repository at this point in the history
Fix resize problems when charts are initially hidden
  • Loading branch information
tannerlinsley committed Sep 19, 2015
2 parents 723c853 + 97cec86 commit efa5ab7
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 81 deletions.
1 change: 1 addition & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var srcFiles = [
'./src/elements/**',
'./src/charts/**',
'./node_modules/color/dist/color.min.js',
'./node_modules/javascript-detect-element-resize/detect-element-resize.js',
'./node_modules/moment/min/moment.min.js'
];

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"inquirer": "^0.5.1",
"jasmine": "^2.3.2",
"jasmine-core": "^2.3.4",
"javascript-detect-element-resize": "git://github.com/chartjs/javascript-detect-element-resize.git",
"jquery": "^2.1.4",
"karma": "^0.12.37",
"karma-chrome-launcher": "^0.2.0",
Expand Down
21 changes: 19 additions & 2 deletions samples/bar.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@
<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="addDataset">Add Dataset</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">
Expand Down Expand Up @@ -64,6 +70,13 @@ <h3>Legend</h3>
data: barChartData,
options: {
responsive: true,
scales: {
xAxes: [{
// So that bars fill the entire width of the grid
categorySpacing: 0,
spacing: 0
}]
}
}
});

Expand Down Expand Up @@ -100,7 +113,7 @@ <h3>Legend</h3>

$('#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);
Expand All @@ -123,6 +136,10 @@ <h3>Legend</h3>
});
updateLegend();
});

$('#show').click(function() {
document.getElementById('container').style.display = '';
});
</script>
</body>

Expand Down
1 change: 1 addition & 0 deletions src/charts/Chart.Doughnut.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
var helpers = Chart.helpers;

var defaultConfig = {
aspectRatio: 1,
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i = 0; i < data.datasets[0].data.length; i++){%><li><span style=\"background-color:<%=data.datasets[0].backgroundColor[i]%>\"><%if(data.labels && i < data.labels.length){%><%=data.labels[i]%><%}%></span></li><%}%></ul>",
};

Expand Down
1 change: 1 addition & 0 deletions src/charts/Chart.PolarArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
var helpers = Chart.helpers;

var defaultConfig = {
aspectRatio: 1,
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i = 0; i < data.datasets[0].data.length; i++){%><li><span style=\"background-color:<%=data.datasets[0].backgroundColor[i]%>\"><%if(data.labels && i < data.labels.length){%><%=data.labels[i]%><%}%></span></li><%}%></ul>",
};

Expand Down
5 changes: 5 additions & 0 deletions src/charts/Chart.Radar.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
var Chart = root.Chart;
var helpers = Chart.helpers;

var defaultConfig = {
aspectRatio: 1,
};

Chart.Radar = function(context, config) {
config.options = helpers.configMerge(defaultConfig, config.options);
config.type = 'radar';

return new Chart(context, config);
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/controller.doughnut.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@

update: function(reset) {

this.chart.outerRadius = (helpers.min([this.chart.chart.width, this.chart.chart.height]) / 2) - this.chart.options.elements.arc.borderWidth / 2;
this.chart.innerRadius = this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1;
this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) / 2) - this.chart.options.elements.arc.borderWidth / 2, 0);
this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length;

this.getDataset().total = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/controller.polarArea.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@
this.chart.scale.generateTicks();
this.chart.scale.buildYLabels();

this.chart.outerRadius = (helpers.min([this.chart.chart.width, this.chart.chart.height]) - this.chart.options.elements.arc.borderWidth / 2) / 2;
this.chart.innerRadius = this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1;
this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) - this.chart.options.elements.arc.borderWidth / 2) / 2, 0);
this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length;

this.getDataset().total = 0;
Expand Down
22 changes: 10 additions & 12 deletions src/core/core.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,11 @@

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;
Expand Down Expand Up @@ -348,19 +350,15 @@
destroy: function destroy() {
this.clear();
helpers.unbindEvents(this, this.events);
var canvas = this.chart.canvas;

// 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];
Expand Down
77 changes: 63 additions & 14 deletions src/core/core.helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -690,17 +690,54 @@
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 ?
Expand All @@ -709,16 +746,19 @@
},
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
Expand Down Expand Up @@ -757,6 +797,15 @@
}
return window.Color(color);
},
addResizeListener = helpers.addResizeListener = function(node, callback) {
if (window.addResizeListener) {
if (node) {
window.addResizeListener(node, callback);
}
} else {
console.log('Add resize listener not found')
}
},
isArray = helpers.isArray = function(obj) {
if (!Array.isArray) {
return Object.prototype.toString.call(arg) === '[object Array]';
Expand Down
43 changes: 23 additions & 20 deletions src/core/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -32,32 +31,36 @@
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;
Expand Down
29 changes: 0 additions & 29 deletions src/core/core.responsive.js

This file was deleted.

Loading

0 comments on commit efa5ab7

Please sign in to comment.