This is an automated email from the ASF dual-hosted git repository. ovilia pushed a commit to branch feat-chord in repository https://gitbox.apache.org/repos/asf/echarts.git
commit c3dda28a9ca3c1e4021aea683c894becb01b479a Author: Ovilia <[email protected]> AuthorDate: Mon Nov 18 18:15:14 2024 +0800 WIP(chord): init chord --- src/chart/chord/ChordPiece.ts | 43 +++++++++ src/chart/chord/ChordSeries.ts | 205 +++++++++++++++++++++++++++++++++++++++++ src/chart/chord/ChordView.ts | 71 ++++++++++++++ src/chart/chord/chordLayout.ts | 40 ++++++++ src/chart/chord/install.ts | 30 ++++++ src/echarts.all.ts | 2 + src/export/charts.ts | 2 + src/export/option.ts | 3 + src/model/Global.ts | 1 + 9 files changed, 397 insertions(+) diff --git a/src/chart/chord/ChordPiece.ts b/src/chart/chord/ChordPiece.ts new file mode 100644 index 000000000..853c86c24 --- /dev/null +++ b/src/chart/chord/ChordPiece.ts @@ -0,0 +1,43 @@ +import * as graphic from '../../util/graphic'; +import SeriesData from '../../data/SeriesData'; +import ChordSeriesModel, { ChordNodeItemOption } from './ChordSeries'; +import { extend } from 'zrender/src/core/util'; +import { getSectorCornerRadius } from '../helper/sectorHelper'; + +export default class ChordPiece extends graphic.Sector { + + constructor(data: SeriesData, idx: number, startAngle: number) { + super(); + + this.z2 = 2; + + const text = new graphic.Text(); + + this.setTextContent(text); + + this.updateData(data, idx, startAngle, true); + } + + updateData(data: SeriesData, idx: number, startAngle?: number, firstCreate?: boolean): void { + const sector = this; + const node = data.graph.getNodeByIndex(idx); + + const seriesModel = data.hostModel as ChordSeriesModel; + const itemModel = node.getModel<ChordNodeItemOption>(); + + // layout position is the center of the sector + const layout = data.getItemLayout(idx) as graphic.Sector['shape']; + // console.log(layout) + + const sectorShape = extend( + getSectorCornerRadius( + itemModel.getModel('itemStyle'), + layout, + true + ), + layout + ); + sector.setShape(sectorShape); + sector.useStyle(data.getItemVisual(idx, 'style')); + } +} diff --git a/src/chart/chord/ChordSeries.ts b/src/chart/chord/ChordSeries.ts new file mode 100644 index 000000000..3cd203b91 --- /dev/null +++ b/src/chart/chord/ChordSeries.ts @@ -0,0 +1,205 @@ +/* +* 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. +*/ + +import * as zrUtil from 'zrender/src/core/util'; +import { + SeriesOption, + SeriesOnCartesianOptionMixin, + SeriesOnPolarOptionMixin, + SeriesOnCalendarOptionMixin, + SeriesOnGeoOptionMixin, + SeriesOnSingleOptionMixin, + OptionDataValue, + RoamOptionMixin, + SeriesLabelOption, + ItemStyleOption, + LineStyleOption, + SymbolOptionMixin, + BoxLayoutOptionMixin, + CircleLayoutOptionMixin, + SeriesLineLabelOption, + StatesOptionMixin, + GraphEdgeItemObject, + OptionDataValueNumeric, + CallbackDataParams, + DefaultEmphasisFocus +} from '../../util/types'; +import Model from '../../model/Model'; +import SeriesModel from '../../model/Series'; +import GlobalModel from '../../model/Global'; +import SeriesData from '../../data/SeriesData'; +import createGraphFromNodeEdge from '../helper/createGraphFromNodeEdge'; + +interface ChordStatesMixin { + emphasis?: DefaultEmphasisFocus +} + +interface ChordEdgeStatesMixin { + emphasis?: DefaultEmphasisFocus +} + +type ChordDataValue = OptionDataValue | OptionDataValue[]; + +export interface ChordNodeStateOption<TCbParams = never> { + itemStyle?: ItemStyleOption<TCbParams> + label?: SeriesLabelOption +} + +export interface ChordNodeItemOption extends ChordNodeStateOption, + StatesOptionMixin<ChordNodeStateOption, ChordStatesMixin> { + + id?: string + name?: string + value?: ChordDataValue +} + +interface ChordEdgeLineStyleOption extends LineStyleOption { + curveness?: number +} + +export interface ChordEdgeStateOption { + lineStyle?: LineStyleOption + label?: SeriesLineLabelOption +} + +export interface ChordEdgeItemOption extends ChordEdgeStateOption, + StatesOptionMixin<ChordEdgeStateOption, ChordEdgeStatesMixin>, + GraphEdgeItemObject<OptionDataValueNumeric> { + + value?: number +} + +export interface ChordSeriesOption + extends SeriesOption<ChordNodeStateOption<CallbackDataParams>, ChordStatesMixin>, + SeriesOnCartesianOptionMixin, SeriesOnPolarOptionMixin, SeriesOnCalendarOptionMixin, + SeriesOnGeoOptionMixin, SeriesOnSingleOptionMixin, + SymbolOptionMixin<CallbackDataParams>, + RoamOptionMixin, + BoxLayoutOptionMixin, + CircleLayoutOptionMixin +{ + type?: 'chord' + + coordinateSystem?: 'none' + + legendHoverLink?: boolean + + clockwise?: boolean + startAngle?: number + endAngle?: number | 'auto' + padAngle?: number + + data?: (ChordNodeItemOption | ChordDataValue)[] + nodes?: (ChordNodeItemOption | ChordDataValue)[] + + edges?: ChordEdgeItemOption[] + links?: ChordEdgeItemOption[] + + edgeLabel?: SeriesLineLabelOption + label?: SeriesLabelOption + + itemStyle?: ItemStyleOption<CallbackDataParams> + lineStyle?: ChordEdgeLineStyleOption +} + +class ChordSeriesModel extends SeriesModel<ChordSeriesOption> { + + static type = 'series.chord'; + readonly type = ChordSeriesModel.type; + + init(option: ChordSeriesOption) { + super.init.apply(this, arguments as any); + } + + getInitialData(option: ChordSeriesOption, ecModel: GlobalModel): SeriesData { + const edges = option.edges || option.links || []; + const nodes = option.data || option.nodes || []; + const self = this; + + if (nodes && edges) { + // auto curveness + // initCurvenessList(this); + const graph = createGraphFromNodeEdge(nodes as ChordNodeItemOption[], edges, this, true, beforeLink); + zrUtil.each(graph.edges, function (edge) { + // createEdgeMapForCurveness(edge.node1, edge.node2, this, edge.dataIndex); + }, this); + return graph.data; + } + + function beforeLink(nodeData: SeriesData, edgeData: SeriesData) { + // Overwrite nodeData.getItemModel to + // nodeData.wrapMethod('getItemModel', function (model) { + + // }); + + // TODO Inherit resolveParentPath by default in Model#getModel? + const oldGetModel = Model.prototype.getModel; + function newGetModel(this: Model, path: any, parentModel?: Model) { + const model = oldGetModel.call(this, path, parentModel); + model.resolveParentPath = resolveParentPath; + return model; + } + + edgeData.wrapMethod('getItemModel', function (model: Model) { + model.resolveParentPath = resolveParentPath; + model.getModel = newGetModel; + return model; + }); + + function resolveParentPath(this: Model, pathArr: readonly string[]): string[] { + if (pathArr && (pathArr[0] === 'label' || pathArr[1] === 'label')) { + const newPathArr = pathArr.slice(); + if (pathArr[0] === 'label') { + newPathArr[0] = 'edgeLabel'; + } + else if (pathArr[1] === 'label') { + newPathArr[1] = 'edgeLabel'; + } + return newPathArr; + } + return pathArr as string[]; + } + } + } + + static defaultOption: ChordSeriesOption = { + // zlevel: 0, + z: 2, + + coordinateSystem: 'none', + + legendHoverLink: true, + + left: 0, + top: 0, + right: 0, + bottom: 0, + width: null, + height: null, + + center: ['50%', '50%'], + radius: ['65%', '75%'], + + startAngle: 90, + endAngle: 'auto', + padAngle: 10 + }; +} + +export default ChordSeriesModel; diff --git a/src/chart/chord/ChordView.ts b/src/chart/chord/ChordView.ts new file mode 100644 index 000000000..fb21221be --- /dev/null +++ b/src/chart/chord/ChordView.ts @@ -0,0 +1,71 @@ +/* +* 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. +*/ + +import ChartView from '../../view/Chart'; +import GlobalModel from '../../model/Global'; +import ExtensionAPI from '../../core/ExtensionAPI'; +import SeriesData from '../../data/SeriesData'; +import ChordSeriesModel from './ChordSeries'; +import ChordPiece from './ChordPiece'; + +class ChordView extends ChartView { + + static readonly type = 'chord'; + readonly type: string = ChordView.type; + + private _data: SeriesData; + + init(ecModel: GlobalModel, api: ExtensionAPI) { + } + + render(seriesModel: ChordSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) { + const data = seriesModel.getData(); + + const oldData = this._data; + const group = this.group; + + data.diff(oldData) + .add(function (newIdx) { + const chordPiece = new ChordPiece(data, newIdx, 90); + data.setItemGraphicEl(newIdx, chordPiece); + group.add(chordPiece); + }) + + .update(function (newIdx, oldIdx) { + const chordPiece = oldData.getItemGraphicEl(oldIdx) as ChordPiece; + chordPiece.updateData(data, newIdx); + group.add(chordPiece); + data.setItemGraphicEl(newIdx, chordPiece); + }) + + .remove(function (oldIdx) { + const chordPiece = oldData.getItemGraphicEl(oldIdx) as ChordPiece; + group.remove(chordPiece); + }) + + .execute(); + + } + + dispose() { + + } +} + +export default ChordView; diff --git a/src/chart/chord/chordLayout.ts b/src/chart/chord/chordLayout.ts new file mode 100644 index 000000000..d9ac7dd45 --- /dev/null +++ b/src/chart/chord/chordLayout.ts @@ -0,0 +1,40 @@ +/* +* 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. +*/ + +import GlobalModel from '../../model/Global'; +import ChordSeriesModel from './ChordSeries'; +import ExtensionAPI from '../../core/ExtensionAPI'; +import { getViewRect, getCircleLayout } from '../../util/layout'; +import SeriesModel from '../../model/Series'; +import { CircleLayoutOptionMixin, SeriesOption } from '../../util/types'; + +export default function chordCircularLayout(ecModel: GlobalModel, api: ExtensionAPI) { + ecModel.eachSeriesByType('chord', function (seriesModel: ChordSeriesModel) { + chordLayout(seriesModel, api); + }); +} + +function chordLayout(seriesModel: ChordSeriesModel, api: ExtensionAPI) { + const viewRect = getViewRect(seriesModel, api); + + const { cx, cy, r, r0 } = getCircleLayout( + seriesModel as unknown as SeriesModel<CircleLayoutOptionMixin & SeriesOption<unknown>>, + api + ); +} diff --git a/src/chart/chord/install.ts b/src/chart/chord/install.ts new file mode 100644 index 000000000..cb0412a04 --- /dev/null +++ b/src/chart/chord/install.ts @@ -0,0 +1,30 @@ +/* +* 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. +*/ + +import { EChartsExtensionInstallRegisters } from '../../extension'; +import ChordView from './ChordView'; +import ChordSeriesModel from './ChordSeries'; +import chordLayout from './chordLayout'; + +export function install(registers: EChartsExtensionInstallRegisters) { + registers.registerChartView(ChordView); + registers.registerSeriesModel(ChordSeriesModel); + + registers.registerLayout(registers.PRIORITY.VISUAL.POST_CHART_LAYOUT, chordLayout); +} \ No newline at end of file diff --git a/src/echarts.all.ts b/src/echarts.all.ts index 5eba7d34c..f53189747 100644 --- a/src/echarts.all.ts +++ b/src/echarts.all.ts @@ -43,6 +43,7 @@ import { TreeChart, TreemapChart, GraphChart, + ChordChart, GaugeChart, FunnelChart, ParallelChart, @@ -127,6 +128,7 @@ use([ TreeChart, TreemapChart, GraphChart, + ChordChart, GaugeChart, FunnelChart, ParallelChart, diff --git a/src/export/charts.ts b/src/export/charts.ts index 4356de914..3ccb85073 100644 --- a/src/export/charts.ts +++ b/src/export/charts.ts @@ -34,6 +34,7 @@ export {install as MapChart} from '../chart/map/install'; export {install as TreeChart} from '../chart/tree/install'; export {install as TreemapChart} from '../chart/treemap/install'; export {install as GraphChart} from '../chart/graph/install'; +export {install as ChordChart} from '../chart/chord/install'; export {install as GaugeChart} from '../chart/gauge/install'; export {install as FunnelChart} from '../chart/funnel/install'; export {install as ParallelChart} from '../chart/parallel/install'; @@ -83,6 +84,7 @@ export { TreeSeriesOption, TreemapSeriesOption, GraphSeriesOption, + ChordSeriesOption, GaugeSeriesOption, FunnelSeriesOption, ParallelSeriesOption, diff --git a/src/export/option.ts b/src/export/option.ts index d25e8197a..a39fe92e6 100644 --- a/src/export/option.ts +++ b/src/export/option.ts @@ -72,6 +72,7 @@ import type {MapSeriesOption as MapSeriesOptionInner} from '../chart/map/MapSeri import type {TreeSeriesOption as TreeSeriesOptionInner} from '../chart/tree/TreeSeries'; import type {TreemapSeriesOption as TreemapSeriesOptionInner} from '../chart/treemap/TreemapSeries'; import type {GraphSeriesOption as GraphSeriesOptionInner} from '../chart/graph/GraphSeries'; +import type {ChordSeriesOption as ChordSeriesOptionInner} from '../chart/chord/ChordSeries'; import type {GaugeSeriesOption as GaugeSeriesOptionInner} from '../chart/gauge/GaugeSeries'; import type {FunnelSeriesOption as FunnelSeriesOptionInner} from '../chart/funnel/FunnelSeries'; import type {ParallelSeriesOption as ParallelSeriesOptionInner} from '../chart/parallel/ParallelSeries'; @@ -187,6 +188,7 @@ export type MapSeriesOption = MapSeriesOptionInner & SeriesInjectedOption; export type TreeSeriesOption = TreeSeriesOptionInner & SeriesInjectedOption; export type TreemapSeriesOption = TreemapSeriesOptionInner & SeriesInjectedOption; export type GraphSeriesOption = GraphSeriesOptionInner & SeriesInjectedOption; +export type ChordSeriesOption = ChordSeriesOptionInner & SeriesInjectedOption; export type GaugeSeriesOption = GaugeSeriesOptionInner & SeriesInjectedOption; export type FunnelSeriesOption = FunnelSeriesOptionInner & SeriesInjectedOption; export type ParallelSeriesOption = ParallelSeriesOptionInner & SeriesInjectedOption; @@ -225,6 +227,7 @@ export interface RegisteredSeriesOption { tree: TreeSeriesOption treemap: TreemapSeriesOption graph: GraphSeriesOption + chord: ChordSeriesOption gauge: GaugeSeriesOption funnel: FunnelSeriesOption parallel: ParallelSeriesOption diff --git a/src/model/Global.ts b/src/model/Global.ts index 7b2e8a339..8cef02375 100644 --- a/src/model/Global.ts +++ b/src/model/Global.ts @@ -120,6 +120,7 @@ const BUILTIN_CHARTS_MAP = { tree: 'TreeChart', treemap: 'TreemapChart', graph: 'GraphChart', + chord: 'ChordChart', gauge: 'GaugeChart', funnel: 'FunnelChart', parallel: 'ParallelChart', --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
