You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2021/10/03 10:52:20 UTC
[echarts] 01/01: wip(ssr): integrate ssr svg output. upgrade ts
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch svg-ssr
in repository https://gitbox.apache.org/repos/asf/echarts.git
commit 44e26a8c9e55adbd33df9a9ad71a2b11cb32a28f
Author: pissang <bm...@gmail.com>
AuthorDate: Sun Oct 3 18:51:17 2021 +0800
wip(ssr): integrate ssr svg output. upgrade ts
---
build/dev-fast.js | 3 +-
package-lock.json | 6 +--
package.json | 2 +-
src/component/toolbox/feature/SaveAsImage.ts | 4 +-
src/core/echarts.ts | 64 +++++++++++++++-----------
src/util/decal.ts | 17 +++++--
src/util/states.ts | 2 +-
test/node/ssr.js | 67 ++++++++++++++++++++++++++++
8 files changed, 129 insertions(+), 36 deletions(-)
diff --git a/build/dev-fast.js b/build/dev-fast.js
index 2a1aacb..8d417e7 100644
--- a/build/dev-fast.js
+++ b/build/dev-fast.js
@@ -26,8 +26,9 @@ const outFilePath = path.resolve(__dirname, '../dist/echarts.js');
const umdMark = '// ------------- WRAPPED UMD --------------- //';
const umdWrapperHead = `
${umdMark}
+typeof window !== 'undefined' ? window.__DEV__ = true
+ : typeof global !== 'undefined' ? global.__DEV__ = true : __DEV__ = true;
(function (root, factory) {
- window.__DEV__ = true;
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['exports'], factory);
diff --git a/package-lock.json b/package-lock.json
index c319fcf..8236e54 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10619,9 +10619,9 @@
}
},
"typescript": {
- "version": "4.3.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
- "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
+ "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
"dev": true
},
"unbzip2-stream": {
diff --git a/package.json b/package.json
index 319d57e..7469582 100644
--- a/package.json
+++ b/package.json
@@ -106,6 +106,6 @@
"socket.io": "2.2.0",
"terser": "^5.3.8",
"ts-jest": "^26.4.3",
- "typescript": "4.3.5"
+ "typescript": "4.4.3"
}
}
diff --git a/src/component/toolbox/feature/SaveAsImage.ts b/src/component/toolbox/feature/SaveAsImage.ts
index c59bb86..6410b87 100644
--- a/src/component/toolbox/feature/SaveAsImage.ts
+++ b/src/component/toolbox/feature/SaveAsImage.ts
@@ -74,6 +74,7 @@ class SaveAsImage extends ToolboxFeature<ToolboxSaveAsImageFeatureOption> {
}
// IE or old Edge
else {
+ // @ts-ignore
if (window.navigator.msSaveOrOpenBlob || isSvg) {
const parts = url.split(',');
// data:[<mime type>][;charset=<charset>][;base64],<encoded data>
@@ -88,13 +89,14 @@ class SaveAsImage extends ToolboxFeature<ToolboxSaveAsImageFeatureOption> {
// (just a url-encoded string through `encodeURIComponent`)
base64Encoded && (bstr = window.atob(bstr));
const filename = title + '.' + type;
+ // @ts-ignore
if (window.navigator.msSaveOrOpenBlob) {
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
- const blob = new Blob([u8arr]);
+ const blob = new Blob([u8arr]);// @ts-ignore
window.navigator.msSaveOrOpenBlob(blob, filename);
}
else {
diff --git a/src/core/echarts.ts b/src/core/echarts.ts
index 8a61c98..b997116 100644
--- a/src/core/echarts.ts
+++ b/src/core/echarts.ts
@@ -327,6 +327,7 @@ type EChartsInitOpts = {
renderer?: RendererType,
devicePixelRatio?: number,
useDirtyRect?: boolean,
+ ssr?: boolean,
width?: number,
height?: number
};
@@ -343,6 +344,8 @@ class ECharts extends Eventful<ECEventDefinition> {
*/
group: string;
+ private _ssr: boolean;
+
private _zr: zrender.ZRenderType;
private _dom: HTMLElement;
@@ -429,8 +432,10 @@ class ECharts extends Eventful<ECEventDefinition> {
devicePixelRatio: opts.devicePixelRatio,
width: opts.width,
height: opts.height,
+ ssr: opts.ssr,
useDirtyRect: opts.useDirtyRect == null ? defaultUseDirtyRect : opts.useDirtyRect
});
+ this._ssr = opts.ssr;
// Expect 60 fps.
this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);
@@ -634,7 +639,10 @@ class ECharts extends Eventful<ECEventDefinition> {
// Ensure zr refresh sychronously, and then pixel in canvas can be
// fetched after `setOption`.
- this._zr.flush();
+ if (!this._ssr) {
+ // not use flush when using ssr mode.
+ this._zr.flush();
+ }
this[PENDING_UPDATE] = null;
this[IN_MAIN_PROCESS_KEY] = false;
@@ -1121,7 +1129,10 @@ class ECharts extends Eventful<ECEventDefinition> {
}
this._disposed = true;
- modelUtil.setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');
+ const dom = this.getDom();
+ if (dom) {
+ modelUtil.setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');
+ }
const chart = this;
const api = chart._api;
@@ -2546,32 +2557,35 @@ export function init(
theme?: string | object,
opts?: EChartsInitOpts
): EChartsType {
- if (__DEV__) {
- if (!dom) {
- throw new Error('Initialize failed: invalid dom.');
+ const isClient = !(opts && opts.ssr);
+ if (isClient) {
+ if (__DEV__) {
+ if (!dom) {
+ throw new Error('Initialize failed: invalid dom.');
+ }
}
- }
- const existInstance = getInstanceByDom(dom);
- if (existInstance) {
- if (__DEV__) {
- console.warn('There is a chart instance already initialized on the dom.');
+ const existInstance = getInstanceByDom(dom);
+ if (existInstance) {
+ if (__DEV__) {
+ console.warn('There is a chart instance already initialized on the dom.');
+ }
+ return existInstance;
}
- return existInstance;
- }
- if (__DEV__) {
- if (isDom(dom)
- && dom.nodeName.toUpperCase() !== 'CANVAS'
- && (
- (!dom.clientWidth && (!opts || opts.width == null))
- || (!dom.clientHeight && (!opts || opts.height == null))
- )
- ) {
- console.warn('Can\'t get DOM width or height. Please check '
- + 'dom.clientWidth and dom.clientHeight. They should not be 0.'
- + 'For example, you may need to call this in the callback '
- + 'of window.onload.');
+ if (__DEV__) {
+ if (isDom(dom)
+ && dom.nodeName.toUpperCase() !== 'CANVAS'
+ && (
+ (!dom.clientWidth && (!opts || opts.width == null))
+ || (!dom.clientHeight && (!opts || opts.height == null))
+ )
+ ) {
+ console.warn('Can\'t get DOM width or height. Please check '
+ + 'dom.clientWidth and dom.clientHeight. They should not be 0.'
+ + 'For example, you may need to call this in the callback '
+ + 'of window.onload.');
+ }
}
}
@@ -2579,7 +2593,7 @@ export function init(
chart.id = 'ec_' + idBase++;
instances[chart.id] = chart;
- modelUtil.setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);
+ isClient && modelUtil.setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);
enableConnect(chart);
diff --git a/src/util/decal.ts b/src/util/decal.ts
index 4058db9..dc26506 100644
--- a/src/util/decal.ts
+++ b/src/util/decal.ts
@@ -28,10 +28,11 @@ import ExtensionAPI from '../core/ExtensionAPI';
import type SVGPainter from 'zrender/src/svg/Painter';
import { brushSingle } from 'zrender/src/canvas/graphic';
import {DecalDashArrayX, DecalDashArrayY, InnerDecalObject, DecalObject} from './types';
+import { SVGVNode } from 'zrender/src/svg/core';
const decalMap = new WeakMap<DecalObject, PatternObject>();
-const decalCache = new LRU<HTMLCanvasElement | SVGElement>(100);
+const decalCache = new LRU<HTMLCanvasElement | SVGVNode>(100);
const decalKeys = [
'symbol', 'symbolSize', 'symbolKeepAspect',
@@ -117,7 +118,7 @@ export function createOrUpdatePatternFromDecal(
cacheKey = keys.join(',') + (isSVG ? '-svg' : '');
const cache = decalCache.get(cacheKey);
if (cache) {
- isSVG ? (pattern as SVGPatternObject).svgElement = cache as SVGElement
+ isSVG ? (pattern as SVGPatternObject).svgElement = cache as SVGVNode
: (pattern as ImagePatternObject).image = cache as HTMLCanvasElement;
}
}
@@ -129,7 +130,12 @@ export function createOrUpdatePatternFromDecal(
const lineBlockLengthY = getLineBlockLengthY(dashArrayY);
const canvas = !isSVG && createCanvas();
- const svgRoot = isSVG && (zr.painter as SVGPainter).createSVGElement('g');
+ const svgRoot: SVGVNode = isSVG && {
+ tag: 'g',
+ attrs: {},
+ key: 'dcl',
+ children: []
+ };
const pSize = getPatternSize();
let ctx: CanvasRenderingContext2D;
if (canvas) {
@@ -284,7 +290,10 @@ export function createOrUpdatePatternFromDecal(
decalOpt.symbolKeepAspect
);
if (isSVG) {
- svgRoot.appendChild((zr.painter as SVGPainter).paintOne(symbol));
+ const symbolVNode = (zr.painter as SVGPainter).renderOneToVNode(symbol);
+ if (symbolVNode) {
+ svgRoot.children.push(symbolVNode);
+ }
}
else {
// Paint to canvas for all other renderers.
diff --git a/src/util/states.ts b/src/util/states.ts
index ac5e01c..3cff899 100644
--- a/src/util/states.ts
+++ b/src/util/states.ts
@@ -216,7 +216,7 @@ function getFromStateStyle(
// Dont consider the animation to emphasis state.
&& animator.__fromStateTransition.indexOf(toStateName) < 0
&& animator.targetName === 'style') {
- animator.saveFinalToTarget(fromState, props);
+ animator.saveTo(fromState, props);
}
}
return fromState;
diff --git a/test/node/ssr.js b/test/node/ssr.js
new file mode 100644
index 0000000..6f4673e
--- /dev/null
+++ b/test/node/ssr.js
@@ -0,0 +1,67 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+const echarts = require('../../dist/echarts');
+const chart = echarts.init(null, null, {
+ renderer: 'svg',
+ ssr: true,
+ width: 510,
+ height: 510
+});
+
+chart.setOption({
+ series: [
+ {
+ name: 'Nightingale Chart',
+ type: 'pie',
+ radius: [25, 250],
+ center: ['50%', '50%'],
+ roseType: 'radius',
+ label: {
+ show: false,
+ },
+ itemStyle: {
+ borderColor: 'white',
+ borderWidth: 4,
+ },
+ labelLine: {
+ show: false,
+ },
+ animationType: 'scale',
+ animationDuration: 500,
+ animationEasing: 'cubicOut',
+ animationDelay(idx) {
+ return (1 - idx / 8) * 500;
+ },
+ data: [
+ { value: 40, name: 'rose 1', itemStyle: { borderRadius: [0, 20] } },
+ { value: 32, name: 'rose 2', itemStyle: { borderRadius: [0, 18] } },
+ { value: 28, name: 'rose 3', itemStyle: { borderRadius: [0, 16] } },
+ { value: 24, name: 'rose 4', itemStyle: { borderRadius: [0, 14] } },
+ { value: 19, name: 'rose 5', itemStyle: { borderRadius: [0, 12] } },
+ { value: 15, name: 'rose 6', itemStyle: { borderRadius: [0, 10] } },
+ { value: 12, name: 'rose 7', itemStyle: { borderRadius: [0, 8] } },
+ { value: 10, name: 'rose 8', itemStyle: { borderRadius: [0, 6] } },
+ ],
+ },
+ ],
+});
+// chart.getZr().animation.update(true);
+const str = chart.getZr().painter.renderToString();
+console.log(str);
+chart.dispose();
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org