This is an automated email from the ASF dual-hosted git repository.

ovilia pushed a commit to branch feat-sankey-roam
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit 396236405809dd697d6f9c64093f3c4a7e1636bd
Author: Ovilia <[email protected]>
AuthorDate: Thu Sep 5 14:49:03 2024 +0800

    feat(sankey): sankey support roam
---
 src/chart/sankey/SankeySeries.ts |  14 +++-
 src/chart/sankey/SankeyView.ts   |  71 ++++++++++++++++++++
 test/sankey-roam.html            | 135 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 218 insertions(+), 2 deletions(-)

diff --git a/src/chart/sankey/SankeySeries.ts b/src/chart/sankey/SankeySeries.ts
index 9dca447ca..1826ea4e7 100644
--- a/src/chart/sankey/SankeySeries.ts
+++ b/src/chart/sankey/SankeySeries.ts
@@ -34,12 +34,14 @@ import {
     GraphEdgeItemObject,
     OptionDataValueNumeric,
     DefaultEmphasisFocus,
-    CallbackDataParams
+    CallbackDataParams,
+    RoamOptionMixin
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import SeriesData from '../../data/SeriesData';
 import { LayoutRect } from '../../util/layout';
 import { createTooltipMarkup } from '../../component/tooltip/tooltipMarkup';
+import View from '../../coord/View';
 
 
 type FocusNodeAdjacency = boolean | 'inEdges' | 'outEdges' | 'allEdges';
@@ -95,7 +97,8 @@ export interface SankeyLevelOption extends 
SankeyNodeStateOption, SankeyEdgeStat
 export interface SankeySeriesOption
     extends SeriesOption<SankeyBothStateOption<CallbackDataParams>, 
ExtraStateOption>,
     SankeyBothStateOption<CallbackDataParams>,
-    BoxLayoutOptionMixin {
+    BoxLayoutOptionMixin,
+    RoamOptionMixin {
     type?: 'sankey'
 
     /**
@@ -148,6 +151,8 @@ class SankeySeriesModel extends 
SeriesModel<SankeySeriesOption> {
     static readonly type = 'series.sankey';
     readonly type = SankeySeriesModel.type;
 
+    coordinateSystem: View;
+
     levelModels: Model<SankeyLevelOption>[];
 
     layoutInfo: LayoutRect;
@@ -297,6 +302,11 @@ class SankeySeriesModel extends 
SeriesModel<SankeySeriesOption> {
 
         layoutIterations: 32,
 
+        // true | false | 'move' | 'scale', see 
module:component/helper/RoamController.
+        roam: false,
+        center: null,
+        zoom: 1,
+
         label: {
             show: true,
             position: 'right',
diff --git a/src/chart/sankey/SankeyView.ts b/src/chart/sankey/SankeyView.ts
index e84b7f7ee..47cf89e51 100644
--- a/src/chart/sankey/SankeyView.ts
+++ b/src/chart/sankey/SankeyView.ts
@@ -31,6 +31,11 @@ import { setLabelStyle, getLabelStatesModels } from 
'../../label/labelStyle';
 import { getECData } from '../../util/innerStore';
 import { isString, retrieve3 } from 'zrender/src/core/util';
 import type { GraphEdge } from '../../data/Graph';
+import RoamController from '../../component/helper/RoamController';
+import type { RoamControllerHost } from '../../component/helper/roamHelper';
+import { onIrrelevantElement } from '../../component/helper/cursorHelper';
+import * as roamHelper from '../../component/helper/roamHelper';
+import View from '../../coord/View';
 
 class SankeyPathShape {
     x1 = 0;
@@ -111,6 +116,17 @@ class SankeyView extends ChartView {
 
     private _data: SeriesData;
 
+    private _controller: RoamController;
+    private _controllerHost: RoamControllerHost;
+
+    init(ecModel: GlobalModel, api: ExtensionAPI): void {
+        this._controller = new RoamController(api.getZr());
+
+        this._controllerHost = {
+            target: this.group
+        } as RoamControllerHost;
+    }
+
     render(seriesModel: SankeySeriesModel, ecModel: GlobalModel, api: 
ExtensionAPI) {
         const sankeyView = this;
         const graph = seriesModel.getGraph();
@@ -131,6 +147,14 @@ class SankeyView extends ChartView {
         group.x = layoutInfo.x;
         group.y = layoutInfo.y;
 
+        const viewCoordSys = seriesModel.coordinateSystem = new View();
+        viewCoordSys.zoomLimit = seriesModel.get('scaleLimit');
+        viewCoordSys.setBoundingRect(layoutInfo.x, layoutInfo.y, width, 
height);
+        viewCoordSys.setCenter(seriesModel.get('center'), api);
+        viewCoordSys.setZoom(seriesModel.get('zoom'));
+
+        this._updateController(seriesModel, ecModel, api);
+
         // generate a bezire Curve for each edge
         graph.eachEdge(function (edge) {
             const curve = new SankeyPath();
@@ -346,6 +370,53 @@ class SankeyView extends ChartView {
     }
 
     dispose() {
+        this._controller && this._controller.dispose();
+        this._controllerHost = null;
+    }
+
+    private _updateController(
+        seriesModel: SankeySeriesModel,
+        ecModel: GlobalModel,
+        api: ExtensionAPI
+    ) {
+        const controller = this._controller;
+        const controllerHost = this._controllerHost;
+        const group = this.group;
+        controller.setPointerChecker(function (e, x, y) {
+            const rect = group.getBoundingRect();
+            rect.applyTransform(group.transform);
+            return rect.contain(x, y)
+                && !onIrrelevantElement(e, api, seriesModel);
+        });
+
+        controller.enable(seriesModel.get('roam'));
+        controllerHost.zoomLimit = seriesModel.get('scaleLimit');
+        controllerHost.zoom = seriesModel.coordinateSystem.getZoom();
+
+        controller
+            .off('pan')
+            .off('zoom')
+            .on('pan', (e) => {
+                roamHelper.updateViewOnPan(controllerHost, e.dx, e.dy);
+                api.dispatchAction({
+                    seriesId: seriesModel.id,
+                    type: 'sankeyRoam',
+                    dx: e.dx,
+                    dy: e.dy
+                });
+            })
+            .on('zoom', (e) => {
+                roamHelper.updateViewOnZoom(controllerHost, e.scale, 
e.originX, e.originY);
+                api.dispatchAction({
+                    seriesId: seriesModel.id,
+                    type: 'sankeyRoam',
+                    zoom: e.scale,
+                    originX: e.originX,
+                    originY: e.originY
+                });
+                // Only update label layout on zoom
+                api.updateLabelLayout();
+            });
     }
 }
 
diff --git a/test/sankey-roam.html b/test/sankey-roam.html
new file mode 100644
index 000000000..ad749941f
--- /dev/null
+++ b/test/sankey-roam.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+
+
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <script src="lib/simpleRequire.js"></script>
+        <script src="lib/config.js"></script>
+        <script src="lib/jquery.min.js"></script>
+        <script src="lib/facePrint.js"></script>
+        <script src="lib/testHelper.js"></script>
+        <!-- <script src="ut/lib/canteen.js"></script> -->
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+        </style>
+
+
+
+        <div id="main0"></div>
+
+
+
+
+
+
+        <script>
+        require([
+            'echarts',
+            // 'map/js/china',
+            // './data/nutrients.json'
+        ], function (echarts) {
+            var option;
+            option = {
+                series: {
+                    type: 'sankey',
+                    layout: 'none',
+                    roam: true,
+                    scaleLimit: {
+                        min: 0.5,
+                        max: 1.5
+                    },
+                    emphasis: {
+                    focus: 'adjacency'
+                    },
+                    data: [
+                    {
+                        name: 'a'
+                    },
+                    {
+                        name: 'b'
+                    },
+                    {
+                        name: 'a1'
+                    },
+                    {
+                        name: 'a2'
+                    },
+                    {
+                        name: 'b1'
+                    },
+                    {
+                        name: 'c'
+                    }
+                    ],
+                    links: [
+                    {
+                        source: 'a',
+                        target: 'a1',
+                        value: 5
+                    },
+                    {
+                        source: 'a',
+                        target: 'a2',
+                        value: 3
+                    },
+                    {
+                        source: 'b',
+                        target: 'b1',
+                        value: 8
+                    },
+                    {
+                        source: 'a',
+                        target: 'b1',
+                        value: 3
+                    },
+                    {
+                        source: 'b1',
+                        target: 'a1',
+                        value: 1
+                    },
+                    {
+                        source: 'b1',
+                        target: 'c',
+                        value: 2
+                    }
+                    ]
+                }
+            };
+            var chart = testHelper.create(echarts, 'main0', {
+                title: [
+                    'Sankey Roam'
+                ],
+                option: option,
+                // height: 300,
+                // buttons: [{text: 'btn-txt', onclick: function () {}}],
+                // recordCanvas: true,
+            });
+        });
+        </script>
+
+
+    </body>
+</html>
+


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to