@visactor/taro-vchart 0.2.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +295 -0
- package/lib/src/components/general-chart/index.d.ts +15 -0
- package/lib/src/components/web-chart/index.d.ts +11 -0
- package/lib/src/index.d.ts +13 -0
- package/lib/src/index.js +316 -0
- package/lib/src/typings/IChartProps.d.ts +45 -0
- package/lib/src/typings/IDomRef.d.ts +17 -0
- package/lib/src/typings/IEvent.d.ts +13 -0
- package/lib/src/typings/IOptions.d.ts +2 -0
- package/lib/src/typings/IVChart.d.ts +2 -0
- package/lib/src/typings/VChartEnvType.d.ts +8 -0
- package/lib/src/typings/index.d.ts +6 -0
- package/lib/src/utils/container-styles/index.d.ts +5 -0
- package/lib/src/utils/index.d.ts +2 -0
- package/lib/src/utils/tt-canvas/index.d.ts +37 -0
- package/package.json +92 -0
package/README.md
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# @visactor/taro-vchart
|
|
2
|
+
|
|
3
|
+
VChart 基于 [Taro](https://docs.taro.zone/docs/) 封装的图表组件。
|
|
4
|
+
|
|
5
|
+
## 环境要求
|
|
6
|
+
|
|
7
|
+
**Taro 版本: >= 3.3.17**
|
|
8
|
+
|
|
9
|
+
> taro 因为小版本有一些不兼容的 break change,所以尽量使用 3.3 版本
|
|
10
|
+
|
|
11
|
+
## 支持环境
|
|
12
|
+
|
|
13
|
+
目前组件支持的环境有:**字节小程序**('tt'),**飞书小程序**('lark'),**浏览器**('h5', 'web')。
|
|
14
|
+
|
|
15
|
+
以上环境通过 `type` 属性进行声明,`type` 属性值及对应环境如下:
|
|
16
|
+
|
|
17
|
+
- `tt` 字节小程序。
|
|
18
|
+
|
|
19
|
+
- `lark` 飞书小程序。
|
|
20
|
+
|
|
21
|
+
- `h5` 浏览器环境, 与`web`等价。
|
|
22
|
+
|
|
23
|
+
- `web` 浏览器环境, 与`h5`等价。
|
|
24
|
+
|
|
25
|
+
### 跨端支持
|
|
26
|
+
|
|
27
|
+
用户如果需要跨多端支持, 需要根据 `Taro.getEnv()` 动态传入 `type` 属性.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<VChart
|
|
31
|
+
type={Taro.getEnv()}
|
|
32
|
+
canvasId="chartId"
|
|
33
|
+
spec={spec}
|
|
34
|
+
style={{ height: '100%', width: '100%' }}
|
|
35
|
+
onChartInit={chart => {}}
|
|
36
|
+
onChartReady={chart => {}}
|
|
37
|
+
onChartUpdate={chart => {}}
|
|
38
|
+
/>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 版本要求
|
|
42
|
+
|
|
43
|
+
**字节小程序端**
|
|
44
|
+
|
|
45
|
+
需要确保 **Taro 版本 >= 3.3.17**
|
|
46
|
+
|
|
47
|
+
> taro 因为小版本有一些不兼容的 break change,所以尽量使用 3.3 版本
|
|
48
|
+
|
|
49
|
+
**飞书小程序端**
|
|
50
|
+
|
|
51
|
+
需要确保 **Taro 版本 >= 3.2.0**, **飞书版本 >= 3.45.0**
|
|
52
|
+
|
|
53
|
+
> taro 因为小版本有一些不兼容的 break change,所以尽量使用 3.3 版本
|
|
54
|
+
|
|
55
|
+
## 安装
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
npm install @visactor/taro-vchart
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## API
|
|
62
|
+
|
|
63
|
+
图表组件使用示例如下:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
<VCHart
|
|
67
|
+
type="tt"
|
|
68
|
+
spec={spec}
|
|
69
|
+
canvasId="pie"
|
|
70
|
+
style={{ height: '35vh', width: '100%' }}
|
|
71
|
+
onChartInit={chart => {
|
|
72
|
+
console.log('init pie');
|
|
73
|
+
}}
|
|
74
|
+
onChartReady={chart => {
|
|
75
|
+
console.log('ready pie');
|
|
76
|
+
}}
|
|
77
|
+
onChartUpdate={chart => {
|
|
78
|
+
console.log('update pie');
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| API | 类型 | 说明 |
|
|
84
|
+
| ------------- | -------- | ------------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| type | string | 配置的环境,目前组件支持的环境有:**字节小程序**('tt'),**飞书小程序**('lark'),**浏览器**('h5', 'web') |
|
|
86
|
+
| canvasId | String | 图表 id, 必确唯一 |
|
|
87
|
+
| spec | Object | 图表配置项, 请参考[VChart 配置项](todo) |
|
|
88
|
+
| style | Object | 图表容器样式 |
|
|
89
|
+
| events | Object[] | 事件绑定配置 |
|
|
90
|
+
| options | Object | 初始化 VChart 实例传入的额外配置项,同 [VChart 实例化配置项](todo) |
|
|
91
|
+
| onChartInit | Function | 图表初始化完后触发的回调 |
|
|
92
|
+
| onChartReady | Function | 图表渲染完毕后触发的回调 |
|
|
93
|
+
| onChartUpdate | Function | 图表更新完毕后触发的回调 |
|
|
94
|
+
|
|
95
|
+
## 快速上手
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import React, { useState } from 'react';
|
|
99
|
+
import { View } from '@tarojs/components';
|
|
100
|
+
import VChart from '@visactor/taro-vchart';
|
|
101
|
+
|
|
102
|
+
export function Pie() {
|
|
103
|
+
// 1. 准备图表配置项与数据
|
|
104
|
+
const [spec, setSpec] = useState({
|
|
105
|
+
data: [
|
|
106
|
+
{
|
|
107
|
+
id: 'data1',
|
|
108
|
+
values: [
|
|
109
|
+
{
|
|
110
|
+
value: 335,
|
|
111
|
+
name: '直接访问'
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
value: 310,
|
|
115
|
+
name: '邮件营销'
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
value: 274,
|
|
119
|
+
name: '联盟广告'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
value: 235,
|
|
123
|
+
name: '视频广告'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
value: 400,
|
|
127
|
+
name: '搜索引擎'
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
type: 'pie',
|
|
133
|
+
outerRadius: 0.6,
|
|
134
|
+
innerRadius: 0.5,
|
|
135
|
+
categoryField: 'name',
|
|
136
|
+
valueField: 'value',
|
|
137
|
+
legends: {
|
|
138
|
+
visible: true
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// 向Chart组件, 传递参数.
|
|
143
|
+
return (
|
|
144
|
+
<View
|
|
145
|
+
style={{
|
|
146
|
+
border: '1px solid #eeeeee',
|
|
147
|
+
width: '90vw'
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
<VChart
|
|
151
|
+
type="tt"
|
|
152
|
+
spec={spec}
|
|
153
|
+
canvasId="pie"
|
|
154
|
+
style={{ height: '35vh', width: '100%' }}
|
|
155
|
+
onChartInit={() => {
|
|
156
|
+
console.log('init pie');
|
|
157
|
+
}}
|
|
158
|
+
onChartReady={() => {
|
|
159
|
+
console.log('ready pie');
|
|
160
|
+
}}
|
|
161
|
+
onChartUpdate={() => {
|
|
162
|
+
console.log('update pie');
|
|
163
|
+
}}
|
|
164
|
+
/>
|
|
165
|
+
</View>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 常用示例
|
|
171
|
+
|
|
172
|
+
### 图表状态更新
|
|
173
|
+
|
|
174
|
+
图表内部, 监听了 `spec` 的变化. 当 spec 变化时, 则会基于新的 `spec` 更新图表。
|
|
175
|
+
|
|
176
|
+
此外用户也可以使用 VChart 实例提供的渲染接口,进行图表的渲染、更新、销毁操作。
|
|
177
|
+
|
|
178
|
+
> 可以通过 `onChartInit` 接口, 获取到 VChart 实例.
|
|
179
|
+
|
|
180
|
+
#### API
|
|
181
|
+
|
|
182
|
+
- `chartInstance.renderAsync()` 更新图表
|
|
183
|
+
|
|
184
|
+
- `chartInstance.release()` 销毁图表
|
|
185
|
+
|
|
186
|
+
- `chartInstance.updateSpec()` 基于 Spec 更新图表
|
|
187
|
+
|
|
188
|
+
- `chartInstance.updateData()` 基于数据更新图表
|
|
189
|
+
|
|
190
|
+
详细使用方法请参考:[VChart API](todo)
|
|
191
|
+
|
|
192
|
+
#### 示例
|
|
193
|
+
|
|
194
|
+
兼容 React 的状态管理方式. 通过 setState 更新配置项, 图表即可重绘.
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import React, { useEffect, useState } from 'react';
|
|
198
|
+
import { View } from '@tarojs/components';
|
|
199
|
+
import VChart from '@visactor/taro-vchart';
|
|
200
|
+
|
|
201
|
+
export function Pie() {
|
|
202
|
+
const [spec, setSpec] = useState({
|
|
203
|
+
data: [
|
|
204
|
+
{
|
|
205
|
+
id: 'data1',
|
|
206
|
+
values: [
|
|
207
|
+
{
|
|
208
|
+
value: 335,
|
|
209
|
+
name: '直接访问'
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
value: 310,
|
|
213
|
+
name: '邮件营销'
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
value: 274,
|
|
217
|
+
name: '联盟广告'
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
value: 235,
|
|
221
|
+
name: '视频广告'
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
value: 400,
|
|
225
|
+
name: '搜索引擎'
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
type: 'pie',
|
|
231
|
+
outerRadius: 0.6,
|
|
232
|
+
innerRadius: 0.5,
|
|
233
|
+
categoryField: 'name',
|
|
234
|
+
valueField: 'value',
|
|
235
|
+
legends: {
|
|
236
|
+
visible: true
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
useEffect(() => {
|
|
241
|
+
setTimeout(() => {
|
|
242
|
+
setSpec({
|
|
243
|
+
data: [
|
|
244
|
+
{
|
|
245
|
+
id: 'data1',
|
|
246
|
+
values: [
|
|
247
|
+
{
|
|
248
|
+
value: 335,
|
|
249
|
+
name: '直接访问'
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
value: 310,
|
|
253
|
+
name: '邮件营销'
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
type: 'pie',
|
|
259
|
+
outerRadius: 0.6,
|
|
260
|
+
innerRadius: 0.5,
|
|
261
|
+
categoryField: 'name',
|
|
262
|
+
valueField: 'value',
|
|
263
|
+
legends: {
|
|
264
|
+
visible: true
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}, 3000);
|
|
268
|
+
}, []);
|
|
269
|
+
|
|
270
|
+
return (
|
|
271
|
+
<View
|
|
272
|
+
style={{
|
|
273
|
+
border: '1px solid #eeeeee',
|
|
274
|
+
width: '90vw'
|
|
275
|
+
}}
|
|
276
|
+
>
|
|
277
|
+
<VChart
|
|
278
|
+
type="tt"
|
|
279
|
+
spec={spec}
|
|
280
|
+
canvasId="pie"
|
|
281
|
+
style={{ height: '35vh', width: '100%' }}
|
|
282
|
+
onChartInit={() => {
|
|
283
|
+
console.log('init pie');
|
|
284
|
+
}}
|
|
285
|
+
onChartReady={() => {
|
|
286
|
+
console.log('ready pie');
|
|
287
|
+
}}
|
|
288
|
+
onChartUpdate={() => {
|
|
289
|
+
console.log('update pie');
|
|
290
|
+
}}
|
|
291
|
+
/>
|
|
292
|
+
</View>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TTCanvas } from '../../utils';
|
|
3
|
+
import { IChartProps, IDomRef } from '../../typings';
|
|
4
|
+
export declare class GeneralChart extends React.Component<IChartProps> {
|
|
5
|
+
ttCanvas: TTCanvas;
|
|
6
|
+
constructor(props: IChartProps);
|
|
7
|
+
componentDidMount(): Promise<void>;
|
|
8
|
+
componentDidUpdate(prevProps: IChartProps): void;
|
|
9
|
+
componentWillUnmount(): void;
|
|
10
|
+
init({ domref, dpr }: {
|
|
11
|
+
domref: IDomRef;
|
|
12
|
+
dpr: number;
|
|
13
|
+
}): void;
|
|
14
|
+
render(): React.JSX.Element;
|
|
15
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { IChartProps } from '../../typings';
|
|
3
|
+
export declare class WebChart extends React.Component<IChartProps> {
|
|
4
|
+
private vchart;
|
|
5
|
+
constructor(props: IChartProps);
|
|
6
|
+
componentDidMount(): void;
|
|
7
|
+
componentWillUnmount(): void;
|
|
8
|
+
componentDidUpdate(prevProps: IChartProps): void;
|
|
9
|
+
render(): React.JSX.Element;
|
|
10
|
+
}
|
|
11
|
+
export default WebChart;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IChartProps, VChartEnvType } from './typings';
|
|
2
|
+
interface IVChartProps extends IChartProps {
|
|
3
|
+
/**
|
|
4
|
+
* 配置环境。
|
|
5
|
+
* - `tt` 字节小程序。
|
|
6
|
+
* - `lark` 飞书小程序。
|
|
7
|
+
* - `h5` 浏览器环境, 与`web`等价。
|
|
8
|
+
* - `web` 浏览器环境, 与`h5`等价。
|
|
9
|
+
*/
|
|
10
|
+
type: VChartEnvType;
|
|
11
|
+
}
|
|
12
|
+
export default function VChart({ type, ...args }: IVChartProps): any;
|
|
13
|
+
export { VChart };
|
package/lib/src/index.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import VChart$1 from '@visactor/vchart/build';
|
|
3
|
+
import { View, Canvas } from '@tarojs/components';
|
|
4
|
+
import Taro from '@tarojs/taro';
|
|
5
|
+
|
|
6
|
+
/*! *****************************************************************************
|
|
7
|
+
Copyright (c) Microsoft Corporation.
|
|
8
|
+
|
|
9
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
10
|
+
purpose with or without fee is hereby granted.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
13
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
14
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
15
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
16
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
17
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
18
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
19
|
+
***************************************************************************** */
|
|
20
|
+
|
|
21
|
+
function __rest(s, e) {
|
|
22
|
+
var t = {};
|
|
23
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
24
|
+
t[p] = s[p];
|
|
25
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
26
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
27
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
28
|
+
t[p[i]] = s[p[i]];
|
|
29
|
+
}
|
|
30
|
+
return t;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
34
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
35
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
36
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
37
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
38
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
39
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class WebChart extends React.Component {
|
|
44
|
+
constructor(props) {
|
|
45
|
+
super(props);
|
|
46
|
+
}
|
|
47
|
+
componentDidMount() {
|
|
48
|
+
const { onChartInit, onChartReady } = this.props;
|
|
49
|
+
this.vchart = new VChart$1(this.props.spec, Object.assign({ dom: `${this.props.canvasId}` }, this.props.options));
|
|
50
|
+
onChartInit && onChartInit(this.vchart);
|
|
51
|
+
this.vchart
|
|
52
|
+
.renderAsync()
|
|
53
|
+
.then(() => {
|
|
54
|
+
onChartReady && onChartReady(this.vchart);
|
|
55
|
+
})
|
|
56
|
+
.catch((e) => {
|
|
57
|
+
console.error(e);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
componentWillUnmount() {
|
|
61
|
+
if (!this.vchart)
|
|
62
|
+
return;
|
|
63
|
+
this.vchart && this.vchart.release();
|
|
64
|
+
}
|
|
65
|
+
componentDidUpdate(prevProps) {
|
|
66
|
+
if (!this.vchart)
|
|
67
|
+
return;
|
|
68
|
+
const { spec, onChartReady } = this.props;
|
|
69
|
+
if (JSON.stringify(prevProps.spec) !== JSON.stringify(spec)) {
|
|
70
|
+
this.vchart.updateSpec(spec, true);
|
|
71
|
+
onChartReady && onChartReady(this.vchart);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
render() {
|
|
75
|
+
const { canvasId, style } = this.props;
|
|
76
|
+
return (React.createElement("div", { style: Object.assign(Object.assign({ position: 'relative' }, style), { padding: 0 }), id: `${canvasId}` }));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
class TTCanvas {
|
|
81
|
+
constructor(props) {
|
|
82
|
+
const { dpr, events, spec, options, domref, mode, onChartInit, onChartReady, onChartUpdate } = props;
|
|
83
|
+
this.domref = domref;
|
|
84
|
+
this.mode = mode || 'miniApp';
|
|
85
|
+
this.dpr = dpr;
|
|
86
|
+
this.spec = spec;
|
|
87
|
+
this.events = events;
|
|
88
|
+
this.options = options;
|
|
89
|
+
/**
|
|
90
|
+
* 三个生命周期函数
|
|
91
|
+
*/
|
|
92
|
+
this.onChartInit = onChartInit;
|
|
93
|
+
this.onChartReady = onChartReady;
|
|
94
|
+
this.onChartUpdate = onChartUpdate;
|
|
95
|
+
/**
|
|
96
|
+
* 图表初始化以及渲染
|
|
97
|
+
*/
|
|
98
|
+
this.init();
|
|
99
|
+
this.renderAsync();
|
|
100
|
+
}
|
|
101
|
+
init() {
|
|
102
|
+
const domref = this.domref;
|
|
103
|
+
this.chartInstance = new VChart$1(Object.assign({ width: domref.width, height: domref.height }, this.spec), Object.assign({ mode: this.mode,
|
|
104
|
+
// 跨端参数
|
|
105
|
+
modeParams: {
|
|
106
|
+
domref,
|
|
107
|
+
force: true,
|
|
108
|
+
canvasIdLists: [`${domref.id}_draw_canvas`, `${domref.id}_tooltip_canvas`, `${domref.id}_hidden_canvas`],
|
|
109
|
+
tooltipCanvasId: `${domref.id}_tooltip_canvas`,
|
|
110
|
+
freeCanvasIdx: 1 // 自由 canvas 索引
|
|
111
|
+
}, dpr: this.dpr, renderCanvas: `${domref.id}_draw_canvas` }, this.options));
|
|
112
|
+
this.onChartInit && this.onChartInit(this.chartInstance);
|
|
113
|
+
// events
|
|
114
|
+
if (this.events) {
|
|
115
|
+
this.events.forEach(event => {
|
|
116
|
+
this.chartInstance.on(event.type, Object.assign(Object.assign({}, event.query), { source: 'chart' }), event.handler);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return this.chartInstance;
|
|
120
|
+
}
|
|
121
|
+
renderAsync() {
|
|
122
|
+
var _a;
|
|
123
|
+
(_a = this.chartInstance) === null || _a === void 0 ? void 0 : _a.renderAsync().then((chart) => {
|
|
124
|
+
this.onChartReady && this.onChartReady(chart);
|
|
125
|
+
return chart;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
updateSpec(props) {
|
|
129
|
+
var _a;
|
|
130
|
+
this.onChartUpdate && this.onChartUpdate(this.chartInstance);
|
|
131
|
+
(_a = this.chartInstance) === null || _a === void 0 ? void 0 : _a.updateSpec(props.spec, true);
|
|
132
|
+
}
|
|
133
|
+
release() {
|
|
134
|
+
/**
|
|
135
|
+
* 修复各种内存泄漏问题
|
|
136
|
+
*/
|
|
137
|
+
if (!this.chartInstance)
|
|
138
|
+
return;
|
|
139
|
+
// 释放: 图表
|
|
140
|
+
this.chartInstance.release();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const style_cs_canvas = {
|
|
145
|
+
width: '100%',
|
|
146
|
+
height: '100%',
|
|
147
|
+
display: 'block',
|
|
148
|
+
margin: '0px',
|
|
149
|
+
position: 'relative',
|
|
150
|
+
zIndex: 1
|
|
151
|
+
};
|
|
152
|
+
const style_cs_canvas_hidden = {
|
|
153
|
+
opacity: 0,
|
|
154
|
+
visibility: 'hidden',
|
|
155
|
+
width: '100%',
|
|
156
|
+
height: '100%',
|
|
157
|
+
position: 'absolute',
|
|
158
|
+
pointerEvents: 'none',
|
|
159
|
+
top: 0,
|
|
160
|
+
left: 0,
|
|
161
|
+
zIndex: 0
|
|
162
|
+
};
|
|
163
|
+
const style_cs_tooltip_canvas = {
|
|
164
|
+
width: '100%',
|
|
165
|
+
height: '100%',
|
|
166
|
+
position: 'absolute',
|
|
167
|
+
pointerEvents: 'none',
|
|
168
|
+
top: 0,
|
|
169
|
+
left: 0,
|
|
170
|
+
zIndex: 2
|
|
171
|
+
};
|
|
172
|
+
const style_container = {
|
|
173
|
+
width: '100%',
|
|
174
|
+
height: '100%',
|
|
175
|
+
position: 'relative'
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
class GeneralChart extends React.Component {
|
|
179
|
+
constructor(props) {
|
|
180
|
+
super(props);
|
|
181
|
+
}
|
|
182
|
+
componentDidMount() {
|
|
183
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
184
|
+
if (!this.props.spec || !this.props.canvasId) {
|
|
185
|
+
if (!this.props.spec)
|
|
186
|
+
console.warn('props.spec are not found');
|
|
187
|
+
if (!this.props.canvasId)
|
|
188
|
+
console.warn('props.canvasId are not found');
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
// 获取domRef
|
|
192
|
+
const getDomRef = () => __awaiter(this, void 0, void 0, function* () {
|
|
193
|
+
return new Promise(resolve => {
|
|
194
|
+
Taro.nextTick(() => {
|
|
195
|
+
Taro.createSelectorQuery()
|
|
196
|
+
.select(`#${this.props.canvasId}_draw_canvas`)
|
|
197
|
+
.boundingClientRect(domref => {
|
|
198
|
+
resolve(domref);
|
|
199
|
+
})
|
|
200
|
+
.exec();
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
/**
|
|
205
|
+
* TODO:
|
|
206
|
+
* 这里是一个很不优雅的写法
|
|
207
|
+
* 具体背景为: 用户在加载页面后, 立刻创建图表, 会报取不domRef的错误.
|
|
208
|
+
* 具体原因是Taro.nextTick()仅执行一次时, 在飞书小程序无法正确取到Dom节点. 经过测试, 调用2次就可以保持正确.
|
|
209
|
+
* 因此在这里被迫做了一个for循环, 多次尝试. 至多取100次.
|
|
210
|
+
*
|
|
211
|
+
* 此外, 这里也无法使用onReady进行操作, 具体请参考: http://taro-docs.jd.com/taro/docs/react-page#onready-
|
|
212
|
+
* 此问题目前仅出现在飞书小程序, 字节小程序正常.
|
|
213
|
+
*/
|
|
214
|
+
const MAX_TIMES = 100;
|
|
215
|
+
for (let i = 0; i < MAX_TIMES; i++) {
|
|
216
|
+
// 获取domRef
|
|
217
|
+
const domref = yield getDomRef();
|
|
218
|
+
if (domref === null || domref === undefined) {
|
|
219
|
+
// 如果不存在, 则重复循环, 最多尝试100次. 确保不会死循环.
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
// 初始化图表
|
|
223
|
+
Taro.getSystemInfo({
|
|
224
|
+
success: res => {
|
|
225
|
+
this.init({ domref, dpr: res.pixelRatio });
|
|
226
|
+
},
|
|
227
|
+
fail: res => {
|
|
228
|
+
console.error(new Error('taro 暂不支持该环境'));
|
|
229
|
+
console.log(res);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
componentDidUpdate(prevProps) {
|
|
237
|
+
if (this.ttCanvas &&
|
|
238
|
+
this.ttCanvas.chartInstance &&
|
|
239
|
+
JSON.stringify(prevProps.spec) !== JSON.stringify(this.props.spec)) {
|
|
240
|
+
this.ttCanvas.updateSpec(this.props);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
componentWillUnmount() {
|
|
244
|
+
this.ttCanvas && this.ttCanvas.release();
|
|
245
|
+
}
|
|
246
|
+
init({ domref, dpr = 2 }) {
|
|
247
|
+
if (!domref) {
|
|
248
|
+
console.error(`未找到 #${this.props.canvasId} 组件`);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
domref.id = this.props.canvasId;
|
|
252
|
+
this.ttCanvas = new TTCanvas({
|
|
253
|
+
dpr: dpr,
|
|
254
|
+
domref,
|
|
255
|
+
spec: this.props.spec,
|
|
256
|
+
events: this.props.events,
|
|
257
|
+
options: this.props.options,
|
|
258
|
+
onChartInit: (chart) => {
|
|
259
|
+
var _a;
|
|
260
|
+
((_a = this.props) === null || _a === void 0 ? void 0 : _a.onChartInit) && this.props.onChartInit(chart);
|
|
261
|
+
},
|
|
262
|
+
onChartReady: (chart) => {
|
|
263
|
+
var _a;
|
|
264
|
+
((_a = this.props) === null || _a === void 0 ? void 0 : _a.onChartReady) && this.props.onChartReady(chart);
|
|
265
|
+
},
|
|
266
|
+
onChartUpdate: (chart) => {
|
|
267
|
+
var _a;
|
|
268
|
+
((_a = this.props) === null || _a === void 0 ? void 0 : _a.onChartUpdate) && this.props.onChartUpdate(chart);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
render() {
|
|
273
|
+
const handleEvent = (event) => {
|
|
274
|
+
const id = event.target.id.split('_')[0];
|
|
275
|
+
if (id === this.props.canvasId && this.ttCanvas.chartInstance) {
|
|
276
|
+
const chartInstance = this.ttCanvas.chartInstance;
|
|
277
|
+
Object.defineProperty(event, 'target', {
|
|
278
|
+
writable: false,
|
|
279
|
+
value: chartInstance.getCanvas() // Tip: 必须设置
|
|
280
|
+
});
|
|
281
|
+
chartInstance.getStage().window.dispatchEvent(event);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const { canvasId, style = {} } = this.props;
|
|
285
|
+
return (React.createElement(View, { key: canvasId, style: Object.assign(Object.assign(Object.assign({}, style_container), style), { padding: 0 }) },
|
|
286
|
+
React.createElement(Canvas, { style: Object.assign({}, style_cs_tooltip_canvas), id: `${canvasId}_tooltip_canvas`, canvasId: `${canvasId}_tooltip_canvas` }),
|
|
287
|
+
React.createElement(Canvas, { onTouchStart: handleEvent, onTouchMove: handleEvent, onTouchEnd: handleEvent, style: style_cs_canvas, id: `${canvasId}_draw_canvas`, canvasId: `${canvasId}_draw_canvas` }),
|
|
288
|
+
React.createElement(Canvas, { style: Object.assign(Object.assign({}, style_cs_canvas), style_cs_canvas_hidden), id: `${canvasId}_hidden_canvas`, canvasId: `${canvasId}_hidden_canvas` })));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function VChart(_a) {
|
|
293
|
+
var { type } = _a, args = __rest(_a, ["type"]);
|
|
294
|
+
const env = type.toLocaleLowerCase();
|
|
295
|
+
const strategies = {
|
|
296
|
+
lark: () => {
|
|
297
|
+
return React.createElement(GeneralChart, Object.assign({}, args));
|
|
298
|
+
},
|
|
299
|
+
tt: () => {
|
|
300
|
+
return React.createElement(GeneralChart, Object.assign({}, args));
|
|
301
|
+
},
|
|
302
|
+
web: () => {
|
|
303
|
+
return React.createElement(WebChart, Object.assign({}, args));
|
|
304
|
+
},
|
|
305
|
+
h5: () => {
|
|
306
|
+
return React.createElement(WebChart, Object.assign({}, args));
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
if (env && strategies[env] !== undefined) {
|
|
310
|
+
return strategies[env].call();
|
|
311
|
+
}
|
|
312
|
+
console.warn(`暂不支持 ${env} 环境`);
|
|
313
|
+
return React.createElement(GeneralChart, Object.assign({}, args));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export { VChart, VChart as default };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
import { IOptions } from './IOptions';
|
|
3
|
+
import { IVChart, ISpec } from './IVChart';
|
|
4
|
+
import { IEvent } from './IEvent';
|
|
5
|
+
interface IChartProps {
|
|
6
|
+
/**
|
|
7
|
+
* 图表 id, 必确唯一
|
|
8
|
+
*/
|
|
9
|
+
canvasId: string;
|
|
10
|
+
/**
|
|
11
|
+
* VChart 图表配置项
|
|
12
|
+
*/
|
|
13
|
+
spec: ISpec;
|
|
14
|
+
/**
|
|
15
|
+
* 图表容器样式
|
|
16
|
+
*/
|
|
17
|
+
style?: CSSProperties;
|
|
18
|
+
/**
|
|
19
|
+
* 初始化 VChart 实例传入的额外配置项,同 VChart 实例化配置项
|
|
20
|
+
*/
|
|
21
|
+
options?: IOptions;
|
|
22
|
+
/**
|
|
23
|
+
* 事件绑定配置
|
|
24
|
+
*/
|
|
25
|
+
events?: IEvent[];
|
|
26
|
+
/**
|
|
27
|
+
* 图表渲染完毕后触发的回调
|
|
28
|
+
* @param chart
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
onChartReady?: (chart: IVChart) => void;
|
|
32
|
+
/**
|
|
33
|
+
* 图表初始化完后触发的回调
|
|
34
|
+
* @param chart
|
|
35
|
+
* @returns
|
|
36
|
+
*/
|
|
37
|
+
onChartInit?: (chart: IVChart) => void;
|
|
38
|
+
/**
|
|
39
|
+
* 图表更新完毕后触发的回调
|
|
40
|
+
* @param chart
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
onChartUpdate?: (chart: IVChart) => void;
|
|
44
|
+
}
|
|
45
|
+
export { IChartProps };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface IDomRef {
|
|
2
|
+
id: string;
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
left: number;
|
|
6
|
+
top: number;
|
|
7
|
+
right: number;
|
|
8
|
+
bottom: number;
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
requestAnimationFrame?: any;
|
|
12
|
+
cancelAnimationFrame?: any;
|
|
13
|
+
getBoundingClientRect?: () => {
|
|
14
|
+
height: number;
|
|
15
|
+
width: number;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EventType, EventQuery, EventCallback, EventParams } from '@visactor/vchart/esm';
|
|
2
|
+
interface IEvent {
|
|
3
|
+
/**
|
|
4
|
+
* 事件的名称
|
|
5
|
+
*/
|
|
6
|
+
type: EventType;
|
|
7
|
+
/**
|
|
8
|
+
* 事件 API 中的事件筛选配置
|
|
9
|
+
*/
|
|
10
|
+
query?: EventQuery;
|
|
11
|
+
handler: EventCallback<EventParams>;
|
|
12
|
+
}
|
|
13
|
+
export { IEvent };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
export declare const style_cs_canvas: CSSProperties;
|
|
3
|
+
export declare const style_cs_canvas_hidden: CSSProperties;
|
|
4
|
+
export declare const style_cs_tooltip_canvas: CSSProperties;
|
|
5
|
+
export declare const style_container: CSSProperties;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { IEvent, IOptions, IVChart, IChartProps, IDomRef } from '../../typings';
|
|
2
|
+
export interface IProps {
|
|
3
|
+
dpr: number;
|
|
4
|
+
domref: IDomRef;
|
|
5
|
+
mode?: string;
|
|
6
|
+
spec: object;
|
|
7
|
+
events?: IEvent[];
|
|
8
|
+
options?: IOptions;
|
|
9
|
+
onChartInit?: any;
|
|
10
|
+
onChartReady?: any;
|
|
11
|
+
onChartUpdate?: any;
|
|
12
|
+
}
|
|
13
|
+
interface ITTCanvas {
|
|
14
|
+
chartInstance: IVChart;
|
|
15
|
+
init: () => IVChart;
|
|
16
|
+
renderAsync: () => void;
|
|
17
|
+
updateSpec: (props: IChartProps) => void;
|
|
18
|
+
release: () => void;
|
|
19
|
+
}
|
|
20
|
+
export declare class TTCanvas implements ITTCanvas {
|
|
21
|
+
private dpr;
|
|
22
|
+
private domref;
|
|
23
|
+
private mode;
|
|
24
|
+
private spec;
|
|
25
|
+
private events?;
|
|
26
|
+
private options?;
|
|
27
|
+
private onChartInit?;
|
|
28
|
+
private onChartReady?;
|
|
29
|
+
private onChartUpdate?;
|
|
30
|
+
chartInstance: IVChart;
|
|
31
|
+
constructor(props: IProps);
|
|
32
|
+
init(): IVChart;
|
|
33
|
+
renderAsync(): void;
|
|
34
|
+
updateSpec(props: IChartProps): void;
|
|
35
|
+
release(): void;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@visactor/taro-vchart",
|
|
3
|
+
"version": "0.2.0-alpha.0",
|
|
4
|
+
"description": "Taro VChart 图表组件",
|
|
5
|
+
"sideEffects": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "lib/src/index.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"lib"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "rm -rf lib && rollup -c",
|
|
13
|
+
"build:tt": "taro build --type tt",
|
|
14
|
+
"build:lark": "taro build --type lark",
|
|
15
|
+
"build:h5": "taro build --type h5",
|
|
16
|
+
"dev:tt": "npm run build:tt -- --watch",
|
|
17
|
+
"dev:lark": "npm run build:lark -- --watch",
|
|
18
|
+
"dev:h5": "npm run build:h5 -- --watch"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"taro",
|
|
22
|
+
"charts",
|
|
23
|
+
"visualization",
|
|
24
|
+
"VChart",
|
|
25
|
+
"animation",
|
|
26
|
+
"storytelling",
|
|
27
|
+
"VisActor",
|
|
28
|
+
"graphics",
|
|
29
|
+
"interaction"
|
|
30
|
+
],
|
|
31
|
+
"homepage": "",
|
|
32
|
+
"bugs": "https://github.com/VisActor/VChart/issues",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "GitHub - VisActor/VChart: The chart library for web and multi-platform",
|
|
36
|
+
"directory": "packages/taro-vchart"
|
|
37
|
+
},
|
|
38
|
+
"author": {
|
|
39
|
+
"name": "VisActor",
|
|
40
|
+
"url": "https://VisActor.io/"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@visactor/vchart": "workspace:1.1.0-beta.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@internal/bundler": "workspace:*",
|
|
48
|
+
"@internal/eslint-config": "workspace:*",
|
|
49
|
+
"@internal/ts-config": "workspace:*",
|
|
50
|
+
"@rushstack/eslint-patch": "~1.1.4",
|
|
51
|
+
"@vitejs/plugin-react": "3.1.0",
|
|
52
|
+
"eslint": "~8.18.0",
|
|
53
|
+
"vite": "3.2.6",
|
|
54
|
+
"typescript": "4.9.5",
|
|
55
|
+
"@babel/core": "7.20.12",
|
|
56
|
+
"@babel/runtime": "7.17.0",
|
|
57
|
+
"@rollup/plugin-typescript": "11.1.0",
|
|
58
|
+
"@tarojs/cli": "3.3.17",
|
|
59
|
+
"@tarojs/components": "3.3.17",
|
|
60
|
+
"@tarojs/mini-runner": "3.3.17",
|
|
61
|
+
"@tarojs/plugin-platform-lark": "^1.0.4",
|
|
62
|
+
"@tarojs/react": "3.3.17",
|
|
63
|
+
"@tarojs/runtime": "3.3.17",
|
|
64
|
+
"@tarojs/taro": "3.3.17",
|
|
65
|
+
"@tarojs/webpack-runner": "3.3.17",
|
|
66
|
+
"@types/react": "^18.0.0",
|
|
67
|
+
"@types/webpack-env": "^1.13.6",
|
|
68
|
+
"@typescript-eslint/eslint-plugin": "5.30.0",
|
|
69
|
+
"@typescript-eslint/parser": "5.30.0",
|
|
70
|
+
"@tarojs/plugin-platform-alipay": "3.3.17",
|
|
71
|
+
"@tarojs/plugin-platform-jd": "3.3.17",
|
|
72
|
+
"@tarojs/plugin-platform-qq": "3.3.17",
|
|
73
|
+
"@tarojs/plugin-platform-swan": "3.3.17",
|
|
74
|
+
"@tarojs/plugin-platform-tt": "3.3.17",
|
|
75
|
+
"@tarojs/plugin-platform-weapp": "3.3.17",
|
|
76
|
+
"babel-preset-taro": "3.3.17",
|
|
77
|
+
"eslint-config-taro": "3.3.17",
|
|
78
|
+
"eslint-plugin-import": "^2.27.5",
|
|
79
|
+
"eslint-plugin-react": "7.30.1",
|
|
80
|
+
"eslint-plugin-react-hooks": "4.6.0",
|
|
81
|
+
"react": "^18.0.0",
|
|
82
|
+
"react-dom": "^18.0.0",
|
|
83
|
+
"rollup": "3.20.5",
|
|
84
|
+
"rollup-plugin-import-css": "^3.0.2",
|
|
85
|
+
"stylelint": "9.3.0",
|
|
86
|
+
"tslib": "2.3.1"
|
|
87
|
+
},
|
|
88
|
+
"publishConfig": {
|
|
89
|
+
"access": "public",
|
|
90
|
+
"registry": "https://registry.npmjs.org/"
|
|
91
|
+
}
|
|
92
|
+
}
|