This is an automated email from the ASF dual-hosted git repository. ovilia pushed a commit to branch dev-5.5.0 in repository https://gitbox.apache.org/repos/asf/echarts-handbook.git
commit a3f570a945f471297ceb23ab2a51d9af43b2cd66 Author: Ovilia <zwl.s...@gmail.com> AuthorDate: Tue Feb 6 17:53:35 2024 +0800 doc: add doc for ssr apache/echarts#18381 --- contents/en/basics/release-note/5-5-0.md | 21 +++++ contents/en/how-to/cross-platform/server.md | 119 +++++++++++++++++++++++--- contents/en/how-to/interaction/drag.md | 2 +- contents/zh/basics/import.md | 8 +- contents/zh/basics/release-note/5-5-0.md | 21 +++++ contents/zh/how-to/cross-platform/server.md | 125 ++++++++++++++++++++++++---- contents/zh/how-to/interaction/drag.md | 2 +- 7 files changed, 266 insertions(+), 32 deletions(-) diff --git a/contents/en/basics/release-note/5-5-0.md b/contents/en/basics/release-note/5-5-0.md new file mode 100644 index 0000000..072982a --- /dev/null +++ b/contents/en/basics/release-note/5-5-0.md @@ -0,0 +1,21 @@ +# Apache ECharts 5.5.0 Features + +## Enhanced ESM Support + +This feature is a significant change to the default ESM package, specifically designed for developer testing and Node.js usage in module customization scenarios. + +Previously, ECharts only exported `*.esm` files in npm (in the lib directory of the npm package). While this worked well in bundlers, it didn’t perform as well in the Node.js runtime and some Node.js-based testing frameworks like vitest and jest. + +With this new feature, we’ve made several changes to improve this: + +- Added `"type": "module"` to package.json +- Added `"exports": {...}"` to package.json +- Added some `package.json` files to the sub-directory, which only contain `"type": "commonjs"`. + +These changes mean that files like `echarts/core.js` can now be resolved as ESM in environments like pure Node.js, vitest, jest, and create-react-app. + +Please note that if using `"exports"`, the files that are not declared in "exports" will be invisible from outside any more. Also, the path must start with `'.'`. + +We’ve also ensured that this new feature is compatible with a variety of environments, including runtime (node / vitest / jest(create-react-app) / ssr / …) and bundlers (webpack / rollup / vite / esbuild / …). + +We’re excited about this new feature and believe it will significantly improve the developer experience. diff --git a/contents/en/how-to/cross-platform/server.md b/contents/en/how-to/cross-platform/server.md index 77d89d7..fd69db2 100644 --- a/contents/en/how-to/cross-platform/server.md +++ b/contents/en/how-to/cross-platform/server.md @@ -18,9 +18,17 @@ Server-side rendering also has some limitations, especially some operations rela ## Server-Side SVG Rendering -If you are using 5.3.0 and newer, we strongly recommend that you use the new zero-dependency server-side string based SVG rendering solution introduced in 5.3.0. +### Server-Side SVG Rendering + +> Version Update: +> +> - 5.3.0: Introduced a new zero-dependency server-side string based SVG rendering solution, and support for initial animation +> - 5.5.0: Added a lightweight client runtime, which allows some interaction without the need to load the full ECharts on the client side + +We introduced a new zero-dependency server-side string based SVG rendering solution in 5.3.0. ```ts +// Server-side code const echarts = require('echarts'); // In SSR mode the first container parameter is not required @@ -48,9 +56,9 @@ The overall code structure is the almost same as in the browser, starting with ` - Firstly, since the SVG is rendered on the server side is string based, we don't need a container to display the rendered content, so we can pass `null` or `undefined` as the first `container` parameter in the `init`. - Then in the third parameter of `init` we need to tell ECharts that we need to enable server-side rendering mode by specifying `ssr: true` in the display. Then ECharts will know it needs to disable the animation loop and event modules. -- We also have to specify the height and width of the chart, so if your chart size needs to be responsive to the container, you may need to think about whether server-side rendering is appropriate for your scenario. +- We also have to specify the `height` and `width` of the chart, so if your chart size needs to be responsive to the container, you may need to think about whether server-side rendering is appropriate for your scenario. -In the browser ECharts automatically renders the result to the page after `setOption` and then determines at each frame if there is an animation that needs to be redrawn, but in NodeJS we don't do this after setting `ssr: true`. Instead, we use `renderToSVGString` to render the current chart to an SVG string, which can then be returned to the front-end via HTTP Response or saved to a local file. +In the browser ECharts automatically renders the result to the page after `setOption` and then determines at each frame if there is an animation that needs to be redrawn, but in Node.js we don't do this after setting `ssr: true`. Instead, we use `renderToSVGString` to render the current chart to an SVG string, which can then be returned to the front-end via HTTP Response or saved to a local file. Response to the browser @@ -58,14 +66,14 @@ Response to the browser res.writeHead(200, { 'Content-Type': 'application/xml' }); -res.write(chart.renderToSVGString()); +res.write(svgStr); // svgStr is the result of chart.renderToSVGString() res.end(); ``` Or save to a local file ```ts -fs.writeFile('bar.svg', chart.renderToSVGString(), 'utf-8'); +fs.writeFile('bar.svg', svgStr, 'utf-8'); ``` Here is a complete server-side SVG rendering example in CodeSandbox. @@ -77,7 +85,7 @@ Here is a complete server-side SVG rendering example in CodeSandbox. sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" ></iframe> -### Animations in Server-side Rendering +#### Animations in Server-side Rendering As you can see in the example above, even using server-side rendering, ECharts can still provide animation effects, which are achieved by embedding CSS animations in the output SVG string. There is no need for additional JavaScript to play the animation. @@ -91,9 +99,9 @@ setOption({ }); ``` -## Server-side Canvas rendering +### Server-side Canvas rendering -If you want the output to be an image rather than an SVG string, or if you're still using an older version, we'd recommend using [node-canvas](https://github.com/Automattic/node-canvas) for server-side rendering, [node-canvas](https://github.com/Automattic/node-canvas) is Canvas implementations on NodeJS that provide an interface that is almost identical to the Canvas in the browser. +If you want the output to be an image rather than an SVG string, or if you're still using an older version, we'd recommend using [node-canvas](https://github.com/Automattic/node-canvas) for server-side rendering, [node-canvas](https://github.com/Automattic/node-canvas) is Canvas implementations on Node.js that provide an interface that is almost identical to the Canvas in the browser. Here's a simple example @@ -139,7 +147,7 @@ Here is a complete example in CodeSandbox sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" ></iframe> -### Loading of images +#### Loading of images [node-canvas](https://github.com/Automattic/node-canvas) provides an `Image` implementation for image loading. If you use to images in your code, we can adapt them using the `setPlatformAPI` interface that was introduced in `5.3.0`. @@ -162,12 +170,18 @@ echarts.setPlatformAPI({ If you are using images from remote, we recommend that you prefetch the image via an http request to get `base64` before passing it on as the URL of the image, to ensure that the image is loaded when render. -## Server-Side Rendering with Hydration +## Server-Side Rendering and Hydration + +### Solution A: Server-Side Rendering with a lazy-loading ECharts on the Client Side + +With the latest version of ECharts, the server-side rendering solution can do the following things along with rendering the chart: + +- Support for initial animation (i.e., the animation that is played when the chart is first rendered) +- Highlighting styles (i.e., the highlighting effect when the mouse moves over a bar in a bar chart) -Features that cannot be supported by server-side rendering include +But there are features that cannot be supported by server-side rendering: - Dynamically changing data -- Highlighting the data item where the mouse is hovered - Clicking on a legend to toggle whether the series is displayed or not - Moving the mouse to show a tooltip - Other interaction-related features @@ -186,3 +200,84 @@ Here is an example of building a CodeSandbox with SVG for server-side rendering ></iframe> As we can see, from the user experience point of view, there is almost no secondary rendering process, and the whole switching effect is very seamless. You can also use a library like [pace-js](https://www.npmjs.com/package/pace-js) to display the loading progress bar during the loading of `echarts.js` as in the above example to solve the problem of no interactive feedback before the ECharts are fully loaded. + +Using server-side rendering with client-side rendering along with a lazy-loading `echarts.js` on the client side is a good solution for scenarios where the first screen needs to be rendered quickly and then the interaction needs to be supported. However, it takes some time to load the `echarts.js` and before it is fully loaded, there is no interactive feedback, in which case, a "Loading" text might be displayed to the user. This is a commonly recommended solution for scenarios where the [...] + +### Solution B: Server-Side Rendering with a lightweight client runtime + +Solution A provides a way for implementing complete interactions, but in some scenarios, we don't need complex interactions, we just hope to be able to perform some simple interactions on the client side based on server-side rendering, such as: clicking the legend to toggle whether the series is displayed. In this case, can we avoid loading at least a few hundred KBs of ECharts code on the client side? + +Starting from version v5.5.0, if the chart only needs the following effects and interactions, it can be achieved through server-side SVG rendering + client-side lightweight runtime: + +- Initial chart animation (implementation principle: the SVG rendered by the server comes with CSS animation) +- Highlight style (implementation principle: the SVG rendered by the server comes with CSS animation) +- Dynamically changing data (implementation principle: the lightweight runtime requests the server for secondary rendering) +- Click the legend to toggle whether the series is displayed (implementation principle: the lightweight runtime requests the server for secondary rendering) + +```html +<div id="chart-container" style="width:800px;height:600px"></div> + +<script src="https://cdn.jsdelivr.net/npm/echarts/ssr/client/dist/index.js"></script> +<script> +const ssrClient = window['echarts-ssr-client']; + +let isSeriesShown = { + a: true, + b: true +}; + +function updateChart(svgStr) { + const container = document.getElementById('chart-container'); + container.innerHTML = svgStr; + + // Use the lightweight runtime to give the chart interactive capabilities + ssrClient.hydrate(main, { + on: { + click: (params) => { + if (params.ssrType === 'legend') { + // Click the legend element, request the server for secondary rendering + isSeriesShown[params.seriesName] = !isSeriesShown[params.seriesName]; + $.get('...?series=' + JSON.stringify(isSeriesShown)).then(svgStr => { + updateChart(svgStr); + }); + } + } + } + }); +} + +// Get the SVG string rendered by the server through an AJAX request +$.get('...').then(svgStr => { + updateChart(svgStr); +}); +</script> +``` + +The server side performs secondary rendering based on the information passed by the client about whether each series is displayed (`isSeriesShown`) and returns a new SVG string. The server-side code [is the same as above](#server-side-svg-rendering), and will not be repeated. + +> About state recording: Compared with pure client-side rendering, developers need to record and maintain some additional information (such as whether each series is displayed in this example). This is inevitable because HTTP requests are stateless. If you want to implement a state, either the client records the state and passes it like the above example, or the server retains the state (for example, through a session, but it requires more server memory and more complex destruction logic [...] + +Using server-side SVG rendering plus client-side lightweight runtime, the advantage is that the client no longer needs to load hundreds of KBs of ECharts code, only needs to load a less than 4KB lightweight runtime code; and from the user experience, very little is sacrificed (supports initial animation, mouse highlighting). The disadvantage is that it requires a certain development cost to maintain additional state information, and it does not support interactions with high real-time re [...] + +## Decide the Rendering Solution According to the Scenario + +Above, we introduced several different rendering solutions, including: + +- Client-side rendering +- Server-side SVG rendering +- Server-side Canvas rendering +- Client-side lightweight runtime rendering + +These four rendering methods can be used in combination. Let's summarize their respective applicable scenarios: + +| Rendering Solution | Loading Volume | Loss of Function and Interaction | Relative Development Workload | Recommended Scenario | +| --- | --- | --- | --- | --- | +| Client-side rendering | ~1000KB | None | Minimum | The first screen load time is not sensitive, and there is a high demand for complete functionality and interaction | +| Client-side rendering ([partial package importing](basics/import#shrinking-bundle-size) on demand) | >400KB | Large: the packages not included cannot use the corresponding functions | Small | The first screen load time is not sensitive, there is no strict requirement for code volume but hope to be as small as possible, only use a small part of ECharts functions, no server resources | +| One-time server-side SVG rendering | ~20KB | Large: unable to dynamically change data, does not support legend toggle series display, does not support tooltips and other interactions with high real-time requirements | Medium | The first screen load time is sensitive, low demand for complete functionality and interaction | +| One-time server-side Canvas rendering | ~200KB | Largest: the same as above and does not support initial animation, larger image volume, blurry when enlarged | Medium | The first screen load time is sensitive, low demand for complete functionality and interaction, platform restrictions cannot use SVG | +| Server-side SVG rendering plus client-side ECharts lazy loading | ~20KB + 1000KB | Medium: cannot interact before lazy loading is completed | Medium | The first screen load time is sensitive, high demand for complete functionality and interaction, the chart is best not needed for interaction immediately after loading | +| Server-side SVG rendering plus client-side lightweight runtime | ~20KB + 4KB, an additional ~20KB per update request | Medium: Cannot implement interactions with high real-time requirements | Large (need to maintain chart status, define client-server interface protocol) | The first screen load time is sensitive, low demand for complete functionality and interaction, very strict requirements for code volume, not strict requirements for interaction real-time | +| Server-side SVG rendering plus client-side ECharts lazy loading, using lightweight runtime before lazy loading is completed | ~20KB + 4KB + 1000KB | Small: Cannot perform complex interactions before lazy loading is completed | Largest | The first screen load time is sensitive, high demand for complete functionality and interaction, sufficient development time | + +Of course, there are some other combination possibilities, but the most common ones are the above. I believe that if you understand the characteristics of these rendering solutions, you can choose the appropriate solution based on your own scenario. diff --git a/contents/en/how-to/interaction/drag.md b/contents/en/how-to/interaction/drag.md index 85a995f..72440d1 100644 --- a/contents/en/how-to/interaction/drag.md +++ b/contents/en/how-to/interaction/drag.md @@ -87,7 +87,7 @@ myChart.setOption({ }); ``` -In the code above, API [convertToPixel](api.html#echartsInstance.convertToPixel) is used to convert data to its "pixel coodinate", based on which each graphic elements can be rendered on canvas. The term "pixel coodinate" means the coordinate is in canvas pixel, whose origin is the top-left of the canvas. In the sentence `myChart.convertToPixel('grid', dataItem)`, the first parameter `'grid'` indicates that `dataItem` should be converted in the first [grid component (cartesian)](${option [...] +In the code above, API [convertToPixel](${mainSitePath}api.html#echartsInstance.convertToPixel) is used to convert data to its "pixel coodinate", based on which each graphic elements can be rendered on canvas. The term "pixel coodinate" means the coordinate is in canvas pixel, whose origin is the top-left of the canvas. In the sentence `myChart.convertToPixel('grid', dataItem)`, the first parameter `'grid'` indicates that `dataItem` should be converted in the first [grid component (carte [...] **Notice:** `convertToPixel` should not be called before the first time that `setOption` called. Namely, it can only be used after coordinate systems (grid/polar/...) initialized. diff --git a/contents/zh/basics/import.md b/contents/zh/basics/import.md index 7415006..255ecfd 100644 --- a/contents/zh/basics/import.md +++ b/contents/zh/basics/import.md @@ -83,6 +83,8 @@ myChart.setOption({ 我们在示例编辑页的“完整代码”标签提供了非常方便的生成按需引入代码的功能。这个功能会根据当前的配置项动态生成最小的按需引入的代码。你可以直接在你的项目中使用。 +> v5.5.0 版本开始使用 ESM 作为默认的模块规范,查看可能的 [Breaking Changes](https://github.com/apache/echarts/pull/19513#issuecomment-1916237700) 以及 [Pull Request](https://github.com/apache/echarts/pull/19513)。 + ## 在 TypeScript 中按需引入 对于使用了 TypeScript 来开发 ECharts 的开发者,我们提供了类型接口来组合出最小的 `EChartsOption` 类型。这个更严格的类型可以有效帮助你检查出是否少加载了组件或者图表。 @@ -106,7 +108,7 @@ import { LabelLayout, UniversalTransition } from 'echarts/features'; import { CanvasRenderer } from 'echarts/renderers'; import type { // 系列类型的定义后缀都为 SeriesOption - BarSeriesOption, + BarSeriesOption, LineSeriesOption } from 'echarts/charts'; import type { @@ -116,8 +118,8 @@ import type { GridComponentOption, DatasetComponentOption } from 'echarts/components'; -import type { - ComposeOption, +import type { + ComposeOption, } from 'echarts/core'; // 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型 diff --git a/contents/zh/basics/release-note/5-5-0.md b/contents/zh/basics/release-note/5-5-0.md new file mode 100644 index 0000000..5c1a25a --- /dev/null +++ b/contents/zh/basics/release-note/5-5-0.md @@ -0,0 +1,21 @@ +# Apache ECharts 5.5.0 特性介绍 + +## 增强的 ESM 支持 + +为了让开发者在测试和 Node.js 环境使用更方便,我们在这个版本中对 ESM 的识别问题进行了优化。 + +以前,ECharts 只在 npm(npm 包的 lib 目录中)导出 `*.esm` 文件。虽然这在 bundlers 环境表现良好,但 Node.js 环境和一些基于 Node.js 的测试框架(如 vitest 和 jest)中的表现并不理想。 + +有了这个新功能,我们做了几个改变以改善这个问题: + +- 在 `package.json` 中添加了 `"type": "module"` +- 在 `package.json` 中添加了 `"exports": {...}` +- 在子目录中添加了一些只包含 `"type": "commonjs"` 的 `package.json` 文件 + +这些改变意味着,像 echarts/core.js 这样的文件现在可以在像纯 Node.js、vitest、jest 和create-react-app 这样的环境中解析为 ESM。 + +请注意,如果使用 "exports",那么在 "exports" 中未声明的文件将无法从外部访问。此外,路径必须以 ’.' 开头。 + +我们还确保了这个新功能与各种环境兼容,包括运行时(Node.js/vitest/jest(create-react-app)/ssr/…)和打包器(webpack / rollup / vite / esbuild / …)。 + +我们相信它将显著提高开发人员的体验,因此很高兴地为大家介绍这个新功能。 diff --git a/contents/zh/how-to/cross-platform/server.md b/contents/zh/how-to/cross-platform/server.md index 9299f4e..bfc1d93 100644 --- a/contents/zh/how-to/cross-platform/server.md +++ b/contents/zh/how-to/cross-platform/server.md @@ -16,11 +16,19 @@ 使用服务端渲染也有一定的局限性,尤其是和交互相关的一些操作无法支持。因此,如果有交互需求,可参考下文的“服务端渲染 Hydration”。 -## 服务端 SVG 渲染 +## 服务端渲染 -如果你在使用 5.3.0 以及更新的版本,我们强烈推荐你使用 5.3.0 里新引入的零依赖的服务端 SVG 字符串渲染方案: +### 服务端 SVG 渲染 + +> 版本更新: +> +> - 5.3.0 版本:使用零依赖的服务端 SVG 字符串渲染方案,并支持图表的初始动画 +> - 5.5.0 版本:新增客户端轻量运行时,客户端无需加载完整 ECharts 即可实现部分交互 + +5.3.0 里新引入了零依赖的服务端 SVG 字符串渲染方案: ```ts +// 服务端代码 const echarts = require('echarts'); // 在 SSR 模式下第一个参数不需要再传入 DOM 对象 @@ -48,9 +56,9 @@ chart = null; - 首先因为在服务端会采用字符串拼接的方式来渲染得到 SVG,我们并不需要容器来展示渲染的内容,所以我们可以在`init`的时候第一个`container`参数传入`null`或者`undefined`。 - 然后我们在`init`的第三个参数中,我们需要通过显示指定`ssr: true`来告诉 ECharts 我们需要开启服务端渲染的模式,该模式下 ECharts 会关闭动画循环的模块以及事件交互的模块。 -- 在服务端渲染中我们也必须要通过`width`和`height`显示的指定图表的高和宽,因此如果你的图表是需要根据容器大小自适应的话,可能需要思考一下服务端渲染是否适合你的场景了。 +- 在服务端渲染中我们也必须要通过`width`和`height`显示的指定图表的高和宽,因此如果你的图表是需要根据容器大小自适应的话,可能需要思考一下服务端渲染是否适合你的场景了。一种可能的解决方案是,首屏获取到图表容器大小后,请求服务端渲染图表,然后在客户端渲染图表;当用户交互改变容器大小时,重新请求服务端渲染。 -在浏览器中我们在`setOption`完之后 ECharts 就会自动进行渲染将结果绘制到页面中,后续也会在每一帧判断是否有动画需要进行重绘。NodeJS 中我们在设置了`ssr: true`后则没有这个过程。取而代之我们使用了`renderToSVGString`,将当前的图表渲染到 SVG 字符串,进一步得再通过 HTTP Response 返回给前端或者缓存到本地。 +在浏览器中我们在`setOption`完之后 ECharts 就会自动进行渲染将结果绘制到页面中,后续也会在每一帧判断是否有动画需要进行重绘。Node.js 中我们在设置了`ssr: true`后则没有这个过程。取而代之我们使用了`renderToSVGString`,将当前的图表渲染到 SVG 字符串,进一步得再通过 HTTP Response 返回给前端或者缓存到本地。 HTTP Response 返回给前端: @@ -58,17 +66,17 @@ HTTP Response 返回给前端: res.writeHead(200, { 'Content-Type': 'application/xml' }); -res.write(chart.renderToSVGString()); +res.write(svgStr); // svgStr 是上面 chart.renderToSVGString() 得到的字符串 res.end(); ``` 或者保存到本地: ```ts -fs.writeFile('bar.svg', chart.renderToSVGString(), 'utf-8'); +fs.writeFile('bar.svg', svgStr, 'utf-8'); ``` -下面是一个完整的在 CodeSandbox 中搭建一个最简单的 NodeJS 服务器然后使用 ECharts 服务端 SVG 渲染的效果: +下面是一个完整的在 CodeSandbox 中搭建一个最简单的 Node.js 服务器然后使用 ECharts 服务端 SVG 渲染的效果: <iframe src="https://codesandbox.io/embed/heuristic-leftpad-oq23t?autoresize=1&codemirror=1&fontsize=12&hidenavigation=1&&theme=dark" style="width:100%; height:400px; border:0; border-radius: 4px; overflow:hidden;" @@ -77,7 +85,7 @@ fs.writeFile('bar.svg', chart.renderToSVGString(), 'utf-8'); sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" ></iframe> -### 服务端渲染中的动画效果 +#### 服务端渲染中的动画效果 上面的例子中可以看到,就算是服务端渲染 ECharts 也可以提供动画效果,这个动画效果是通过在输出的 SVG 字符串中嵌入 CSS 动画实现的。并不需要额外的 JavaScript 再去控制动画。 @@ -91,9 +99,9 @@ setOption({ }); ``` -## 服务端 Canvas 渲染 +### 服务端 Canvas 渲染 -如果你希望输出的是一张图片而非 SVG 字符串,或者你还在使用更老的版本,我们会推荐使用 [node-canvas](https://github.com/Automattic/node-canvas) 来实现 ECharts 的服务渲染,[node-canvas](https://github.com/Automattic/node-canvas) 是在 NodeJS 上的一套 Canvas 实现,它提供了跟浏览器中 Canvas 几乎一致的接口。 +如果你希望输出的是一张图片而非 SVG 字符串,或者你还在使用更老的版本,我们会推荐使用 [node-canvas](https://github.com/Automattic/node-canvas) 来实现 ECharts 的服务渲染,[node-canvas](https://github.com/Automattic/node-canvas) 是在 Node.js 上的一套 Canvas 实现,它提供了跟浏览器中 Canvas 几乎一致的接口。 下面是一个简单的例子 @@ -130,7 +138,7 @@ res.write(buffer); res.end(); ``` -下面是一个完整的在 CodeSandbox 中搭建一个最简单的 NodeJS 服务器然后使用 ECharts 服务端 Canvas 渲染的效果: +下面是一个完整的在 CodeSandbox 中搭建一个最简单的 Node.js 服务器然后使用 ECharts 服务端 Canvas 渲染的效果: <iframe src="https://codesandbox.io/embed/apache-echarts-canvas-ssr-demo-e340rt?autoresize=1&codemirror=1&fontsize=12&hidenavigation=1&&theme=dark" style="width:100%; height:400px; border:0; border-radius: 4px; overflow:hidden;" @@ -139,7 +147,7 @@ res.end(); sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" ></iframe> -### 图片的加载 +#### 图片的加载 [node-canvas](https://github.com/Automattic/node-canvas) 提供了图片加载的`Image`实现,如果你在图表中使用了到了图片,我们可以使用`5.3.0`新增的`setPlatformAPI`接口来适配。 @@ -162,12 +170,18 @@ echarts.setPlatformAPI({ 如果你的图片是需要远程获取的,我们建议你通过 http 请求先预取该图片得到`base64`之后再作为图片的 URL 传入,这样可以保证在 Response 输出的时候图片是加载完成的。 -## 服务端渲染 Hydration +## 服务端渲染与客户端二次渲染 + +### 方案一:首屏服务端渲染与客户端渲染懒加载 + +最新版本的 ECharts 服务端 SVG 渲染除了完成图表的渲染外,支持的功能包括: + +- 图表初始动画(例如:柱状图初始化时的柱子上升动画) +- 高亮样式(例如:鼠标移动到柱状图柱子上时的高亮效果) -服务端渲染无法支持的功能包括: +但仅使用服务端渲染无法支持的功能包括: - 动态改变数据 -- 高亮鼠标所在的数据项 - 点击图例切换系列是否显示 - 移动鼠标显示提示框 - 其他交互相关的功能 @@ -186,3 +200,84 @@ echarts.setPlatformAPI({ ></iframe> 我们可以看到,从用户体验的角度,几乎感受不到二次渲染的过程,整个切换效果是非常无缝衔接的。你也可以像上面的例子中一样,在加载 `echarts.js` 的过程中使用 [pace-js](https://www.npmjs.com/package/pace-js) 之类的库实现显示加载进度条的效果,来解决 ECharts 尚未完全加载完之前没有交互反馈的问题。 + +使用服务端渲染 SVG 加上客户端 ECharts 懒加载的方式,其优点是,能够在首屏快速展示图表,而懒加载完成后可以实现所有 ECharts 的功能和交互;而缺点是,懒加载完整的 ECharts 需要一定时间,在加载完成前无法实现除高亮之外的用户交互(在这种情况下,开发者可以通过显示“加载中”来解决无交互反馈带来的困惑)。这个方案也是目前比较推荐的对首屏加载时间敏感,对功能交互完整性要求高的方案。 + +### 方案二:首屏服务端渲染与客户端轻量运行时 + +方案一给出了实现完整交互的方案,但是有些场景下,我们并不需要很复杂的交互,只是希望在服务端渲染的基础上,能够在客户端进行一些简单的交互,例如:点击图例切换系列是否显示。这种情况下,我们能否不在客户端加载至少需要几百 KB 的 ECharts 代码呢? + +从 v5.5.0 版本起,如果图表只需要以下效果和交互,可以通过服务端 SVG 渲染 + 客户端轻量运行时来实现: + +- 图表初始动画(实现原理:服务端渲染的 SVG 带有 CSS 动画) +- 高亮样式(实现原理:服务端渲染的 SVG 带有 CSS 动画) +- 动态改变数据(实现原理:轻量运行时请求服务器进行二次渲染) +- 点击图例切换系列是否显示(实现原理:轻量运行时请求服务器进行二次渲染) + +```html +<div id="chart-container" style="width:800px;height:600px"></div> + +<script src="https://cdn.jsdelivr.net/npm/echarts/ssr/client/dist/index.js"></script> +<script> +const ssrClient = window['echarts-ssr-client']; + +let isSeriesShown = { + a: true, + b: true +}; + +function updateChart(svgStr) { + const container = document.getElementById('chart-container'); + container.innerHTML = svgStr; + + // 使用轻量运行时赋予图表交互能力 + ssrClient.hydrate(main, { + on: { + click: (params) => { + if (params.ssrType === 'legend') { + // 点击图例元素,请求服务器进行二次渲染 + isSeriesShown[params.seriesName] = !isSeriesShown[params.seriesName]; + $.get('...?series=' + JSON.stringify(isSeriesShown)).then(svgStr => { + updateChart(svgStr); + }); + } + } + } + }); +} + +// 通过 AJAX 请求获取服务端渲染的 SVG 字符串 +$.get('...').then(svgStr => { + updateChart(svgStr); +}); +</script> +``` + +服务器端根据客户端传来的每个系列是否显示的信息(`isSeriesShown`)进行二次渲染,返回新的 SVG 字符串。服务端代码[同上文](#服务端-svg-渲染),不再赘述。 + +> 关于状态记录:上述这种开发方式和纯客户端渲染的相比,开发者需要记录并维护一些额外的信息(例如这个例子中每个系列是否显示)。这是不可避免的,因为 HTTP 请求本身是无状态的,如果要实现有状态,要么像上面的例子这样由客户端记录状态并传递,要么服务器保留状态(例如通过 session,但需要耗费更多的服务器内存以及更复杂的销毁逻辑所以并不推荐)。 + +使用服务端 SVG 渲染加上客户端轻量运行时的方式,其优点是,客户端不再需要加载几百 KB 的 ECharts 代码,只需要加载一个不到 4KB 的轻量运行时代码;并且从用户体验的角度牺牲很少(支持初始动画、鼠标高亮)。而缺点是,需要一定的开发成本来维护额外的状态信息,并且无法支持实时性要求高的交互(例如移动鼠标显示提示框)。总体来说,**推荐在对代码体积有非常严格要求的环境使用**。 + +## 根据场景决定渲染方案 + +上面,我们介绍了几种不同的渲染方案,包括: + +- 客户端渲染 +- 服务端 SVG 渲染 +- 服务端 Canvas 渲染 +- 客户端轻量运行时渲染 + +这四种渲染方式可以结合使用,我们再来总结一下它们各自适用的场景: + +| 渲染方案 | 加载体积 | 功能及交互损失 | 相对开发工作量 | 推荐场景 | +| --- | --- | --- | --- | --- | +| 客户端渲染 | ~1000KB | 无 | 最小 | 首屏加载时间不敏感,对功能交互完整性要求高 | +| 客户端渲染([按需引用](basics/import#按需引入-echarts-图表和组件)部分包) | >400KB | 大:没有引入的包就无法使用对应功能 | 小 | 首屏加载时间不敏感,对代码体积没有严格要求但是希望尽可能小,仅使用 ECharts 的一小部分功能,没有服务器资源 | +| 一次性服务端 SVG 渲染 | ~20KB | 大:无法动态改变数据、不支持图例切换系列是否显示、不支持提示框等实时性要求高的交互 | 中 | 首屏加载时间敏感,对功能交互完整性要求低 | +| 一次性服务端 Canvas 渲染 | ~200KB | 最大:同上且不支持初始动画、图片体积更大、放大会模糊 | 中 | 首屏加载时间敏感,对功能交互完整性要求低,平台限制无法使用 SVG | +| 服务端 SVG 渲染加客户端懒加载 ECharts | ~20KB + 1000KB | 中:懒加载完成前无法交互 | 中 | 首屏加载时间敏感,对功能交互完整性要求高,最好图表不会在加载后立刻需要交互 | +| 服务端 SVG 渲染加客户端轻量运行时 | ~20KB + 4KB,每次更新请求额外 ~20KB | 中:无法实现实时性要求高的交互 | 大(需要维护图表状态、定义客户端服务端接口协议) | 首屏加载时间敏感,对功能交互完整性要求低,对代码体积有非常严格要求,交互实时性要求不严格 | +| 服务端 SVG 渲染加客户端懒加载 ECharts,懒加载完成前使用轻量运行时 | ~20KB + 4KB + 1000KB | 小:在懒加载完成前无法进行复杂交互 | 最大 | 首屏加载时间敏感,对功能交互完整性要求高,有充分的开发时间 | + +当然,还存在一些其他的组合可能性,但最常用的就是以上几种,相信如果你了解了这些渲染方案的特点,就可以根据自己的场景选择合适的方案了。 diff --git a/contents/zh/how-to/interaction/drag.md b/contents/zh/how-to/interaction/drag.md index 8b32dc4..2b3e2f6 100644 --- a/contents/zh/how-to/interaction/drag.md +++ b/contents/zh/how-to/interaction/drag.md @@ -84,7 +84,7 @@ myChart.setOption({ }); ``` -上面的代码中,使用 [convertToPixel](api.html#echartsInstance.convertToPixel) 这个 API,进行了从 data 到“像素坐标”的转换,从而得到了每个圆点应该在的位置,从而能绘制这些圆点。`myChart.convertToPixel('grid', dataItem)` 这句话中,第一个参数 `'grid'` 表示 `dataItem` 在 [grid](${optionPath}grid) 这个组件中(即直角坐标系)中进行转换。所谓“像素坐标”,就是以 echarts 容器 dom element 的左上角为零点的以像素为单位的坐标系中的坐标。 +上面的代码中,使用 [convertToPixel](${mainSitePath}api.html#echartsInstance.convertToPixel) 这个 API,进行了从 data 到“像素坐标”的转换,从而得到了每个圆点应该在的位置,从而能绘制这些圆点。`myChart.convertToPixel('grid', dataItem)` 这句话中,第一个参数 `'grid'` 表示 `dataItem` 在 [grid](${optionPath}grid) 这个组件中(即直角坐标系)中进行转换。所谓“像素坐标”,就是以 echarts 容器 dom element 的左上角为零点的以像素为单位的坐标系中的坐标。 注意这件事需要在第一次 setOption 后再进行,也就是说,须在坐标系([grid](${optionPath}grid))初始化后才能调用 `myChart.convertToPixel('grid', dataItem)`。 --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org For additional commands, e-mail: commits-h...@echarts.apache.org