Skip to content

Commit

Permalink
[add] Proxy Element abstract class of ECharts elements
Browse files Browse the repository at this point in the history
  • Loading branch information
TechQuery committed Feb 17, 2024
1 parent 30e4a56 commit 5a7c5d6
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 101 deletions.
56 changes: 11 additions & 45 deletions source/component/ECharts/Chart.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import { JsxProps } from 'dom-renderer';
import { ECElementEvent, EChartsOption } from 'echarts';
import { EChartsOption } from 'echarts';
import { ECharts, init } from 'echarts/core';
import { ECBasicOption } from 'echarts/types/dist/shared';
import {
CustomElement,
parseDOM,
proxyPrototype,
toHyphenCase
} from 'web-utility';
import { parseDOM } from 'web-utility';

import { ProxyElement } from './Proxy';
import {
BUILTIN_CHARTS_MAP,
BUITIN_COMPONENTS_MAP,
ChartType,
ECChartOptionName,
ECComponentOptionName,
EventKeyPattern,
ZRElementEventHandler,
ZRElementEventName,
loadChart,
Expand All @@ -33,17 +28,14 @@ export interface EChartsElementProps
initOptions?: Parameters<typeof init>[2];
}

export class EChartsElement extends HTMLElement implements CustomElement {
#props: EChartsElementProps & EChartsOption = {};
export type EChartsElementState = EChartsElementProps & EChartsOption;

export class EChartsElement extends ProxyElement<EChartsElementState> {
#type: ChartType;
#core?: ECharts;
#eventHandlers: [ZRElementEventName, ZRElementEventHandler, string?][] = [];
#eventData = [];

toJSON() {
return this.#core?.getOption();
}

set type(value: ChartType) {
this.#type = value;
this.setAttribute('type', value);
Expand All @@ -57,9 +49,6 @@ export class EChartsElement extends HTMLElement implements CustomElement {
constructor() {
super();

proxyPrototype(this, this.#props, (key, value) =>
this.setProperty(key.toString(), value)
);
this.attachShadow({ mode: 'open' }).append(
parseDOM('<div style="height: 100%" />')[0]
);
Expand All @@ -75,14 +64,14 @@ export class EChartsElement extends HTMLElement implements CustomElement {
async #init(type: ChartType) {
await loadRenderer(type);

const { theme, initOptions } = this.#props;
const { theme, initOptions, ...props } = this.toJSON();

this.#core = init(
this.shadowRoot.firstElementChild as HTMLDivElement,
theme,
initOptions
);
this.setOption(this.#props);
this.setOption(props);

for (const [event, handler, selector] of this.#eventHandlers)
if (selector) this.onChild(event, selector, handler);
Expand Down Expand Up @@ -111,32 +100,9 @@ export class EChartsElement extends HTMLElement implements CustomElement {
}

setProperty(key: string, value: any) {
const oldValue = this.#props[key],
name = toHyphenCase(key),
eventName = key.slice(2) as ECElementEvent['type'];
this.#props[key] = value;

switch (typeof value) {
case 'object':
if (!value) this.removeAttribute(name);
break;
case 'boolean':
if (value) super.setAttribute(name, name + '');
else super.removeAttribute(name);
break;
case 'function':
if (EventKeyPattern.test(key)) this.on(eventName, value);
break;
default:
if (value != null) super.setAttribute(name, value + '');
else if (
EventKeyPattern.test(key) &&
typeof oldValue === 'function'
)
this.off(eventName, value);
else super.removeAttribute(name);
}
this.setOption(this.#props);
super.setProperty(key, value);

this.setOption(this.toJSON());
}

on(event: ZRElementEventName, handler: ZRElementEventHandler) {
Expand Down
65 changes: 9 additions & 56 deletions source/component/ECharts/Option.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import { JsxProps } from 'dom-renderer';
import { EChartsOption } from 'echarts';
import { ECElementEvent } from 'echarts/core';
import {
CustomElement,
HyphenCase,
PickSingle,
proxyPrototype,
toCamelCase,
toHyphenCase
} from 'web-utility';
import { HyphenCase, PickSingle, toCamelCase, toHyphenCase } from 'web-utility';

import { EChartsElement } from './Chart';
import { ProxyElement } from './Proxy';
import {
BUILTIN_CHARTS_MAP,
BUITIN_COMPONENTS_MAP,
Expand All @@ -21,16 +14,7 @@ import {
ZRElementEventName
} from './utility';

export abstract class ECOptionElement
extends HTMLElement
implements CustomElement
{
#data: EChartsOption = {};

toJSON() {
return this.#data;
}

export abstract class ECOptionElement extends ProxyElement<EChartsOption> {
get chartTagName() {
return toCamelCase(this.tagName.split('-')[1].toLowerCase());
}
Expand All @@ -43,16 +27,8 @@ export abstract class ECOptionElement
return [this.chartTagName, this['type']].filter(Boolean).join('.');
}

constructor() {
super();

proxyPrototype(this, this.#data, (key, value) =>
this.setProperty(key.toString(), value)
);
}

connectedCallback() {
for (const [key, value] of Object.entries(this.#data))
for (const [key, value] of Object.entries(this.toJSON()))
if (EventKeyPattern.test(key) && typeof value === 'function')
this.on(
key.slice(2) as ZRElementEventName,
Expand All @@ -62,42 +38,19 @@ export abstract class ECOptionElement
}

setProperty(key: string, value: any) {
const oldValue = this.#data[key],
name = toHyphenCase(key),
eventName = key.slice(2) as ECElementEvent['type'];
this.#data[key] = value;

switch (typeof value) {
case 'object':
if (!value) this.removeAttribute(name);
break;
case 'boolean':
if (value) super.setAttribute(name, name + '');
else super.removeAttribute(name);
break;
case 'function':
if (EventKeyPattern.test(key)) this.on(eventName, value);
break;
default:
if (value != null) super.setAttribute(name, value + '');
else if (
EventKeyPattern.test(key) &&
typeof oldValue === 'function'
)
this.off(eventName, value);
else super.removeAttribute(name);
}
super.setProperty(key, value);

if (this.isConnected) this.update();
}

update() {
const data = this.toJSON();

this.dispatchEvent(
new CustomEvent('optionchange', {
bubbles: true,
detail: {
[this.chartTagName]: this.isSeries
? [this.#data]
: this.#data
[this.chartTagName]: this.isSeries ? [data] : data
}
})
);
Expand Down
54 changes: 54 additions & 0 deletions source/component/ECharts/Proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ECElementEvent } from 'echarts';
import { CustomElement, proxyPrototype, toHyphenCase } from 'web-utility';

import { EventKeyPattern } from './utility';

export abstract class ProxyElement<T extends object>
extends HTMLElement
implements CustomElement
{
#data = {} as T;

toJSON() {
return this.#data;
}

constructor() {
super();

proxyPrototype(this, this.#data, (key, value) =>
this.setProperty(key.toString(), value)
);
}

abstract on(event: string, handler: (event: any) => any): any;
abstract off(event: string, handler: (event: any) => any): any;

setProperty(key: string, value: any) {
const oldValue = this.#data[key],
name = toHyphenCase(key),
eventName = key.slice(2) as ECElementEvent['type'];
this.#data[key] = value;

switch (typeof value) {
case 'object':
if (!value) this.removeAttribute(name);
break;
case 'boolean':
if (value) super.setAttribute(name, name + '');
else super.removeAttribute(name);
break;
case 'function':
if (EventKeyPattern.test(key)) this.on(eventName, value);
break;
default:
if (value != null) super.setAttribute(name, value + '');
else if (
EventKeyPattern.test(key) &&
typeof oldValue === 'function'
)
this.off(eventName, value);
else super.removeAttribute(name);
}
}
}

1 comment on commit 5a7c5d6

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for wuhan2020 ready!

✅ Preview
https://wuhan2020-fumy53u5n-techquery.vercel.app

Built with commit 5a7c5d6.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.