Tooltip throws "Cannot read properties of null (reading 'getParsed')" after a responsive chart's canvas is detached
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 82/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- javascript
- Ambito
- data-visualization, frontend
Direzione di ricerca
Inizia da src/plugins/plugin.tooltip.js ed esamina Tooltip._getActiveElements, che l’issue identifica come il filtro che non funziona; confronta il controllo del dataset esistente con il ciclo di vita del controller descritto per i grafici scollegati. Riproduci il problema con la pagina fornita e un evento del puntatore accodato durante lo scollegamento. Il lavoro è completato quando l’evento non genera più errori dopo lo scollegamento e il tooltip continua a funzionare correttamente per i grafici collegati.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Expected behavior
A pointer event that reaches a chart after its canvas leaves the DOM does nothing.
Current behavior
The tooltip throws:
TypeError: Cannot read properties of null (reading 'getParsed')
at Tooltip._getActiveElements (plugin.tooltip.js)
at Tooltip.handleEvent
at Object.afterEvent
at Chart._eventHandler
at listener
at platform.dom.js (throttled proxy, requestAnimationFrame)
When a responsive chart's canvas is detached, the detached handler in bindResponsiveEvents calls this._stop(), which destroys every dataset meta, and then _resize(0, 0). The user event listeners stay bound and chart.ctx stays set, so the chart.ctx !== null check in createProxyAndListen lets a pointer event that was queued for the next frame through.
The tooltip still holds its last active elements. The chart is now 0×0, so the event is outside the chart area, and _getActiveElements filters lastActive:
return lastActive.filter(i =>
this.chart.data.datasets[i.datasetIndex] &&
this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined
);
The dataset is still in chart.data.datasets, so getDatasetMeta() builds a new meta with controller: null, and .getParsed() throws.
#11596 added the datasets[i.datasetIndex] check for a dataset that was removed. This is a case where the dataset is still there but its controller is gone.
Reproducible sample
Self-contained page:
<div id="wrap" style="width:400px;height:300px"><canvas id="c"></canvas></div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
<script>
const chart = new Chart(document.getElementById('c'), {
type: 'bar',
data: { labels: ['a', 'b', 'c'], datasets: [{ label: 'x', data: [3, 5, 2] }] },
options: { animation: false },
});
const pointAtBar = () => {
const rect = chart.canvas.getBoundingClientRect();
const bar = chart.getDatasetMeta(0).data[1];
chart.canvas.dispatchEvent(new MouseEvent('mousemove', {
clientX: rect.left + bar.x,
clientY: rect.top + bar.y + 5,
}));
};
const frame = () => new Promise((resolve) => requestAnimationFrame(resolve));
(async () => {
await frame();
await frame();
pointAtBar(); // the tooltip becomes active
await frame();
await frame();
pointAtBar(); // throttled: runs on the next frame
document.getElementById('wrap').remove(); // detach: chart._stop()
})();
</script>
The second event runs after the detach and throws.
Optional extra steps/info to reproduce
In an app, this happens when a framework removes a chart from the page while the pointer is over it and destroys the chart a little later. Examples are a route transition, or vue-chartjs's destroyDelay, which keeps the chart alive for a short time after its component unmounts. We see it in production from Chrome 156 on Windows.
Possible solution
Skip a meta that has no controller in the filter:
return lastActive.filter(i => {
const { controller } = this.chart.getDatasetMeta(i.datasetIndex);
return this.chart.data.datasets[i.datasetIndex]
&& controller
&& controller.getParsed(i.index) !== undefined;
});
Another option is to clear the active elements of the chart and the tooltip in _stop(), so nothing refers to a destroyed controller.
Context
No response
chart.js version
v4.6.1 (the same code is on master, src/plugins/plugin.tooltip.js)
Browser name and version
Chrome 156; also reproduced in headless Chromium
Link to your project
No response
- Lingua principale
- JavaScript
- Stelle
- 67.8k
- Fork
- 12k
- Merge medio
- 6h 15m
- PR unite (30g)
- 3
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Nessuna guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di chartjs/Chart.js
-
Numeric tick formatter gives repeated labels in scientific notation and with bounds: 'data'Forse già presa @RClaudiuM l’ha presa 5 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
-
linear axis: "reverse" breaks tick align 'inner'Forse già presa @SrkianFardin25 l’ha presa 6 giorni fa. Apertatype: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 77/100
I maintainer di solito rispondono entro 1 giorno
-
fill: 'stack': a dataset's whole fill disappears when its x differs from the line below by ≤ 1e-6 px (happens in animations)Forse già presa @ump45nose l’ha presa 42 giorni fa. Apertatype: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
I maintainer di solito rispondono entro 1 giorno
-
Legend pointStyle: 'line' does not apply dataset borderDash patternForse già presa @HuzaifaChaudary l’ha presa 75 giorni fa. Apertatype: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di chartjs/Chart.js
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
-
good first issue help wanted javascript up-for-grabs
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
andrewsiah/agentswarm-data-tasks#307 ·
I maintainer di solito rispondono entro 1 giorno
-
needs-triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
coder/claudecode.nvim#588 ·
I maintainer di solito rispondono entro 1 giorno
-
area: web tech debt
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
digitalbazaar/http-client#60 ·