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]

Reply via email to