我目前在chart.js中使用react集成有一个雷达图。
我惊讶地注意到,当我更新数据时,它只是从以前的数据集平滑地过渡到新的数据集,而不是显示一个全新的图。
我感兴趣的是了解它在底层是如何工作的,老实说,我不能理解,至少从看代码来看。
第一:我对React的理解是,当一个道具或状态改变时,它会计算新的DOM,然后合并新的DOM和当前的DOM,只应用两者之间的差异。然而,chartjs似乎是作为一个Canvas元素实现的。
chartjs与react的集成并没有做太多。以Radar图为例,它是这样做的
export const Radar = /* #__PURE__ */ createTypedChart('radar', RadarController);
,它只是声明了一个<Chart>
元素,然后让ChartJS来绘制它。实际上,在ChartJS中,我们有这样的代码,它基本上管理Canvas元素它很聪明地使用动画等来执行过渡。这我理解(相对):很多动画和过渡辅助功能,但这对我来说是有意义的。然而,这部分是纯JavaScript。没有任何东西知道React。
不合理的是react同步系统是如何与这个JavaScript库集成的,这样props/state的状态失效就会同步到动画中,而不是完全重写Canvas元素。我似乎在react-chartjs-2中找不到这个神奇的地方。
正如您所解释的那样,canvas元素没有被更改,因此它被重用。要使图表动画化,chart.js本身有一个更新方法。React-chartjs-2使用了一个useeffect函数来检查你传递给它的数据是否发生了变化。如果是这种情况,它会调用chart.js本身的update函数,它们会处理动画并自行更新:
useEffect(() => {
if (!chartRef.current) return;
if (redraw) {
destroyChart();
setTimeout(renderChart);
} else {
chartRef.current.update();
}
}, [redraw, options, data.labels, data.datasets]);
https://github.com/reactchartjs/react-chartjs-2/blob/4a010540ac01b1e4b299705ddd93f412df4875d1/src/chart.tsx L78-L87
这是我在深入研究代码库之后对整个过程的理解。我已经尝试尽可能详细地链接到我正在谈论的代码的确切行。希望有帮助:
-
从您共享的代码片段开始:
export const Radar = /* #__PURE__ */ createTypedChart('radar', RadarController);
-
如果您通过import语句跟踪RadarController,您会看到它是从
获取的。chart.js
-
现在我们移动到Chart.js代码并查找这个控制器RadarController。它位于src/controllers/controller.radar.js文件中。
-
在该文件中,您可以看到一个更新函数
-
这个函数然后用点信息调用updateElements
-
这个函数获取新的点位置,然后在属性中设置并传递给updateElement函数
-
这个updateElement函数直接把我们带到core.datasetController
-
在这里,您可以看到一个检查图表是否在directUpdateMode中的条件。如果不是,它调用一个函数_resolveAnimations
-
在这个函数中,你会看到新的Animations(args)对象
-
这最终把我们带到了核心。动画文件,包含所有动画相关的信息和处理。
-
我在这里发现了一个有趣的地方:这似乎是使点移动到改变位置的美丽运动。
-
您可以进一步探索这个动画类以获得更详细的理解
本质上,它是js部分在引擎盖下促进平滑过渡,这就是它是如何做到的。React代码本质上就像Chart.js的包装器,用新值调用这个更新方法。
你可以在这里看到:https://github.com/reactchartjs/react-chartjs-2/blob/master/src/chart.tsx
react-chartjs-2库创建了一个添加画布的组件,当props更新时,组件会创建/更新一个使用渲染画布的内部Chart对象。
从我看到的动画开始时,道具被改变。
路径为props->react-chartjs-2 component->chart object->animation