Skip to content

Commit 67d35a1

Browse files
committed
feat: support vchart rotate plugin
1 parent 41d438b commit 67d35a1

File tree

9 files changed

+239
-0
lines changed

9 files changed

+239
-0
lines changed

packages/vchart/src/core/factory.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import type { IBaseTriggerOptions, ITriggerConstructor } from '../interaction/in
2525
import type { IComposedEventConstructor } from '../index-harmony-simple';
2626
import type { ITooltipProcessorConstructor } from '../component/tooltip/processor/interface';
2727
import type { ITooltip } from '../component';
28+
import type { IVChartPluginConstructor } from '../plugin/vchart';
2829

2930
export class Factory {
3031
private static _charts: { [key: string]: IChartConstructor } = {};
@@ -42,6 +43,7 @@ export class Factory {
4243
private static _animations: { [key: string]: (params?: any, preset?: any) => MarkAnimationSpec } = {};
4344
private static _implements: { [key: string]: (...args: any) => void } = {};
4445
private static _chartPlugin: { [key: string]: IChartPluginConstructor } = {};
46+
private static _vChartPlugin: { [key: string]: IVChartPluginConstructor } = {};
4547
private static _componentPlugin: { [key: string]: IComponentPluginConstructor } = {};
4648
private static _formatter: (
4749
text: string | number | string[] | number[],
@@ -117,6 +119,9 @@ export class Factory {
117119
static registerChartPlugin(key: string, plugin: IChartPluginConstructor) {
118120
Factory._chartPlugin[key] = plugin;
119121
}
122+
static registerVChartPlugin(key: string, plugin: IVChartPluginConstructor) {
123+
Factory._vChartPlugin[key] = plugin;
124+
}
120125
static registerComponentPlugin(key: string, plugin: IComponentPluginConstructor) {
121126
Factory._componentPlugin[key] = plugin;
122127
}
@@ -269,6 +274,10 @@ export class Factory {
269274
return Object.values(Factory._chartPlugin);
270275
}
271276

277+
static getVChartPlugins() {
278+
return Object.values(Factory._vChartPlugin);
279+
}
280+
272281
static getComponentPlugins() {
273282
return Object.values(Factory._componentPlugin);
274283
}

packages/vchart/src/core/interface.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,12 @@ export interface IVChart {
555555

556556
/** 获取当前容器宽高 */
557557
getCurrentSize: () => IContainerSize;
558+
559+
/** 旋转图表 需要注册插件 */
560+
rotate90WithTransform?: (rotateDom: HTMLElement) => void;
561+
562+
/** 取消图表旋转 */
563+
cancelTransform?: (rotateDom: HTMLElement) => void;
558564
}
559565

560566
export interface IGlobalConfig {

packages/vchart/src/core/vchart.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ import type { IGeoCoordinate } from '../component/geo';
115115
import { registerGesturePlugin } from '../plugin/other';
116116
import { registerElementHighlight } from '../interaction/triggers/element-highlight';
117117
import { registerElementSelect } from '../interaction/triggers/element-select';
118+
import type { IVChartPluginService } from '../plugin/vchart/interface';
119+
import { VChartPluginService } from '../plugin/vchart/plugin-service';
118120

119121
export class VChart implements IVChart {
120122
readonly id = createID();
@@ -357,6 +359,8 @@ export class VChart implements IVChart {
357359
private _isReleased: boolean;
358360

359361
private _chartPlugin?: IChartPluginService;
362+
private _vChartPlugin?: IVChartPluginService;
363+
360364
private _onResize?: () => void;
361365

362366
constructor(spec: ISpec, options: IInitOption) {
@@ -2148,6 +2152,14 @@ export class VChart implements IVChart {
21482152
// 插件生命周期
21492153
this._chartPluginApply('onInit', this._spec);
21502154
}
2155+
2156+
const vChartPluginList = Factory.getVChartPlugins();
2157+
if (vChartPluginList.length > 0) {
2158+
this._vChartPlugin = new VChartPluginService(this);
2159+
this._vChartPlugin.load(vChartPluginList.map(p => new p()));
2160+
// 插件生命周期
2161+
this._vChartPlugin.onInit();
2162+
}
21512163
}
21522164

21532165
private _chartPluginApply(funcName: keyof IChartPluginService, ...args: any[]) {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './register';
2+
export * from './interface';
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { IVChart } from '../../core/interface';
2+
import type { IBasePlugin, IBasePluginService, MaybePromise } from '../base/interface';
3+
4+
export interface IVChartPlugin<T extends IVChartPluginService = any> extends IBasePlugin<T> {
5+
specKey?: string;
6+
onInit?: (service: T) => MaybePromise<void>;
7+
}
8+
9+
export interface IVChartPluginConstructor {
10+
readonly pluginType: 'vchart';
11+
readonly specKey?: string;
12+
readonly type: string;
13+
new (): IVChartPlugin;
14+
}
15+
16+
export interface IVChartPluginService<T extends IVChartPlugin = any> extends IBasePluginService<T> {
17+
globalInstance: IVChart;
18+
onInit?: () => MaybePromise<void>;
19+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { IVChartPlugin, IVChartPluginService } from './interface';
2+
import type { IVChart } from '../../core';
3+
import { BasePluginService } from '../base/base-plugin-service';
4+
5+
export class VChartPluginService<T extends IVChartPlugin = IVChartPlugin>
6+
extends BasePluginService<T>
7+
implements IVChartPluginService<T>
8+
{
9+
globalInstance: IVChart;
10+
11+
constructor(globalInstance: IVChart) {
12+
super();
13+
this.globalInstance = globalInstance;
14+
}
15+
16+
onInit() {
17+
this._plugins.forEach(plugin => {
18+
plugin.onInit && plugin.onInit(this);
19+
});
20+
}
21+
22+
releaseAll(): void {
23+
super.releaseAll();
24+
this.globalInstance = null;
25+
}
26+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { Factory } from '../../core/factory';
2+
import type { IVChartPluginConstructor } from './interface';
3+
4+
export const registerVChartPlugin = (plugin: IVChartPluginConstructor) => {
5+
Factory.registerVChartPlugin(plugin.type, plugin);
6+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './rotate';
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import type { IAABBBounds, Matrix } from '@visactor/vutils';
2+
import { BasePlugin } from '../../base/base-plugin';
3+
import type { IVChartPlugin, IVChartPluginService } from '../interface';
4+
import { registerVChartPlugin } from '../register';
5+
import type { IVChart } from '../../../core/interface';
6+
import {
7+
matrixAllocate,
8+
transformPointForCanvas,
9+
mapToCanvasPointForCanvas,
10+
registerGlobalEventTransformer,
11+
registerWindowEventTransformer,
12+
vglobal
13+
} from '@visactor/vrender-core';
14+
15+
export class RotatePlugin extends BasePlugin implements IVChartPlugin {
16+
static readonly pluginType: 'vchart' = 'vchart';
17+
18+
static readonly specKey = 'rotate';
19+
20+
static readonly type: string = 'rotatePlugin';
21+
readonly type: string = 'rotatePlugin';
22+
23+
private rotateDegree: number;
24+
private matrix: Matrix;
25+
private vglobal_mapToCanvasPoint: any; // 保存vrender中vglobal的mapToCanvasPoint原方法
26+
private _vchart: IVChart;
27+
28+
constructor() {
29+
super(RotatePlugin.type);
30+
}
31+
32+
onInit(service: IVChartPluginService) {
33+
const { globalInstance: vchart } = service;
34+
if (!vchart) {
35+
return;
36+
}
37+
this._vchart = vchart;
38+
//将函数rotate90WithTransform绑定到table实例上,一般情况下插件不需要将api绑定到table实例上,可以直接自身实现某个api功能
39+
vchart.rotate90WithTransform = this.rotate90WithTransform;
40+
vchart.cancelTransform = this.cancelTransform;
41+
}
42+
43+
rotate90WithTransform = (rotateDom: HTMLElement) => {
44+
this.rotateDegree = 90;
45+
const rotateCenter =
46+
rotateDom.clientWidth < rotateDom.clientHeight
47+
? Math.max(rotateDom.clientWidth, rotateDom.clientHeight) / 2
48+
: Math.min(rotateDom.clientWidth, rotateDom.clientHeight) / 2;
49+
const domRect = this._vchart.getContainer().getBoundingClientRect();
50+
const x1 = domRect.left;
51+
const y1 = domRect.top;
52+
const x2 = domRect.right;
53+
const y2 = domRect.bottom;
54+
55+
rotateDom.style.transform = 'rotate(90deg)';
56+
rotateDom.style.transformOrigin = `${rotateCenter}px ${rotateCenter}px`;
57+
const getRect = () => {
58+
return {
59+
x1,
60+
y1,
61+
x2,
62+
y2
63+
} as IAABBBounds;
64+
};
65+
// 获取视口尺寸的通用方法
66+
const getViewportDimensions = () => {
67+
// 浏览器环境
68+
if (typeof window !== 'undefined') {
69+
return {
70+
width: window.innerWidth || document.documentElement.clientWidth,
71+
height: window.innerHeight || document.documentElement.clientHeight
72+
};
73+
}
74+
// 如果有 vglobal 上的方法可以使用
75+
if (vglobal && 'getViewportSize' in vglobal && vglobal.getViewportSize) {
76+
// @ts-ignore
77+
return vglobal.getViewportSize();
78+
}
79+
// 默认使用容器的尺寸
80+
return rotateDom.getBoundingClientRect();
81+
};
82+
83+
const getMatrix = () => {
84+
const viewPortWidth = getViewportDimensions().width; //获取整个视口的尺寸
85+
const domRect = this._vchart.getContainer().getBoundingClientRect(); //TODO 这个地方应该获取窗口的宽高 最好能从vglobal上直接获取
86+
const x1 = domRect.top;
87+
const y1 = viewPortWidth - domRect.right;
88+
89+
const matrix = matrixAllocate.allocate(1, 0, 0, 1, 0, 0);
90+
matrix.translate(x1, y1);
91+
const centerX = rotateCenter - x1;
92+
const centerY = rotateCenter - y1;
93+
matrix.translate(centerX, centerY);
94+
matrix.rotate(Math.PI / 2);
95+
matrix.translate(-centerX, -centerY);
96+
this.matrix = matrix;
97+
return matrix;
98+
};
99+
registerGlobalEventTransformer(vglobal, this._vchart.getContainer(), getMatrix, getRect, transformPointForCanvas);
100+
registerWindowEventTransformer(
101+
this._vchart.getStage().window,
102+
this._vchart.getContainer(),
103+
getMatrix,
104+
getRect,
105+
transformPointForCanvas
106+
);
107+
this.vglobal_mapToCanvasPoint = vglobal.mapToCanvasPoint;
108+
vglobal.mapToCanvasPoint = mapToCanvasPointForCanvas;
109+
//transformPointForCanvas和mapToCanvasPointForCanvas时相对应的
110+
//具体逻辑在 VRender/packages/vrender-core/src/common/event-transformer.ts中
111+
// 可以自定义这两个函数 来修改事件属性,transformPointForCanvas中将坐标转换后存放了_canvasX _canvasY,mapToCanvasPointForCanvas中加以利用
112+
// 在VTable的touch文件中,利用到了_canvasX _canvasY 所以如果自定义上面两个函数也需提供_canvasX _canvasY
113+
};
114+
cancelTransform = (rotateDom: HTMLElement) => {
115+
this.rotateDegree = 0;
116+
rotateDom.style.transform = 'none';
117+
rotateDom.style.transformOrigin = 'none';
118+
const domRect = this._vchart.getContainer().getBoundingClientRect();
119+
const x1 = domRect.left;
120+
const y1 = domRect.top;
121+
const x2 = domRect.right;
122+
const y2 = domRect.bottom;
123+
124+
const getRect = () => {
125+
return {
126+
x1,
127+
y1,
128+
x2,
129+
y2
130+
} as IAABBBounds;
131+
};
132+
const getMatrix = () => {
133+
const matrix = matrixAllocate.allocate(1, 0, 0, 1, 0, 0);
134+
matrix.translate(x1, y1);
135+
return matrix;
136+
};
137+
registerGlobalEventTransformer(vglobal, this._vchart.getContainer(), getMatrix, getRect, transformPointForCanvas);
138+
registerWindowEventTransformer(
139+
this._vchart.getStage().window,
140+
this._vchart.getContainer(),
141+
getMatrix,
142+
getRect,
143+
transformPointForCanvas
144+
);
145+
vglobal.mapToCanvasPoint = this.vglobal_mapToCanvasPoint;
146+
};
147+
148+
release() {
149+
this._vchart = null;
150+
this.vglobal_mapToCanvasPoint = null;
151+
this.matrix = null;
152+
super.release();
153+
}
154+
}
155+
156+
export const registerRotatePlugin = () => {
157+
registerVChartPlugin(RotatePlugin);
158+
};

0 commit comments

Comments
 (0)