fix(web): fix Chart.js sizing after HTMX swaps on all dashboard pages
Two-part fix for charts going tiny on range changes (especially 3m) and staying broken after subsequent navigations: 1. dashboard_base.html: global htmx:beforeSwap handler destroys any Chart.js instances in the swap target before HTMX replaces the DOM. Without this, the old chart's ResizeObserver remains attached to the parent container and interferes with the newly created chart instance's dimension calculations. 2. All chart pages (positioning, supply, warehouse, weather): afterSwap handler now wraps chart resize in requestAnimationFrame, ensuring the browser has completed layout before Chart.js measures container dimensions. MA toggle state is also restored inside the rAF callback after resize. Root cause: chart init scripts run synchronously during innerHTML swap, before browser layout is complete. Fast server responses (e.g. 3m = small dataset) gave even less time for layout, making the timing issue reproducible. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -167,6 +167,19 @@
|
||||
<!-- HTMX -->
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
|
||||
<!-- Destroy Chart.js instances before HTMX swaps canvas-containing elements.
|
||||
Without this, the old chart's ResizeObserver stays alive on the parent container
|
||||
and fights the new chart instance, producing wrong dimensions after the swap. -->
|
||||
<script>
|
||||
document.addEventListener('htmx:beforeSwap', function(e) {
|
||||
if (typeof Chart === 'undefined') return;
|
||||
e.detail.target.querySelectorAll('canvas').forEach(function(canvas) {
|
||||
var chart = Chart.getChart(canvas);
|
||||
if (chart) chart.destroy();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% include "_feedback_widget.html" %}
|
||||
|
||||
{% block scripts %}{% endblock %}
|
||||
|
||||
@@ -104,7 +104,12 @@ function toggleMA(key) {
|
||||
document.addEventListener('htmx:afterSwap', function (e) {
|
||||
if (e.detail.target.id === 'positioning-canvas') {
|
||||
document.getElementById('positioning-canvas').classList.remove('canvas-loading');
|
||||
// Re-apply MA checkbox state after swap
|
||||
requestAnimationFrame(function() {
|
||||
['priceChart', 'cotChart'].forEach(function(id) {
|
||||
var c = Chart.getChart(id);
|
||||
if (c) c.resize();
|
||||
});
|
||||
// Re-apply MA checkbox state after resize
|
||||
var ma20 = document.getElementById('ma20-toggle');
|
||||
var ma50 = document.getElementById('ma50-toggle');
|
||||
var chart = Chart.getChart('priceChart');
|
||||
@@ -113,6 +118,7 @@ document.addEventListener('htmx:afterSwap', function (e) {
|
||||
chart.data.datasets[2].hidden = !ma50.checked;
|
||||
chart.update();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -71,6 +71,12 @@ function setFilter(key, val) {
|
||||
document.addEventListener('htmx:afterSwap', function (e) {
|
||||
if (e.detail.target.id === 'supply-canvas') {
|
||||
document.getElementById('supply-canvas').classList.remove('canvas-loading');
|
||||
requestAnimationFrame(function() {
|
||||
['supplyDemandChart', 'stuChart', 'topCountriesChart'].forEach(function(id) {
|
||||
var c = Chart.getChart(id);
|
||||
if (c) c.resize();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -66,6 +66,12 @@ function setFilter(key, val) {
|
||||
document.addEventListener('htmx:afterSwap', function (e) {
|
||||
if (e.detail.target.id === 'warehouse-canvas') {
|
||||
document.getElementById('warehouse-canvas').classList.remove('canvas-loading');
|
||||
requestAnimationFrame(function() {
|
||||
['stocksChart', 'agingChart', 'byPortChart'].forEach(function(id) {
|
||||
var c = Chart.getChart(id);
|
||||
if (c) c.resize();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -188,6 +188,12 @@ function setFilter(key, val) {
|
||||
document.addEventListener('htmx:afterSwap', function (e) {
|
||||
if (e.detail.target.id === 'weather-canvas') {
|
||||
document.getElementById('weather-canvas').classList.remove('canvas-loading');
|
||||
requestAnimationFrame(function() {
|
||||
['globalStressChart', 'locStressChart', 'locTempChart'].forEach(function(id) {
|
||||
var c = Chart.getChart(id);
|
||||
if (c) c.resize();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user