GraphView.js 13.3 KB
Newer Older
L
lang 已提交
1

L
lang 已提交
2 3
define(function (require) {

L
lang 已提交
4 5
    var SymbolDraw = require('../helper/SymbolDraw');
    var LineDraw = require('../helper/LineDraw');
L
lang 已提交
6
    var RoamController = require('../../component/helper/RoamController');
P
pah100 已提交
7
    var roamHelper = require('../../component/helper/roamHelper');
8
    var cursorHelper = require('../../component/helper/cursorHelper');
L
lang 已提交
9

L
lang 已提交
10
    var graphic = require('../../util/graphic');
L
lang 已提交
11
    var adjustEdge = require('./adjustEdge');
L
lang 已提交
12 13 14 15 16 17 18 19
    var zrUtil = require('zrender/core/util');

    var nodeOpacityPath = ['itemStyle', 'normal', 'opacity'];
    var lineOpacityPath = ['lineStyle', 'normal', 'opacity'];

    function getItemOpacity(item, opacityPath) {
        return item.getVisual('opacity') || item.getModel().get(opacityPath);
    }
L
lang 已提交
20

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
    function fadeOutItem(item, opacityPath, opacityRatio) {
        var el = item.getGraphicEl();

        var opacity = getItemOpacity(item, opacityPath);
        if (opacityRatio != null) {
            opacity == null && (opacity = 1);
            opacity *= opacityRatio;
        }

        el.downplay && el.downplay();
        el.traverse(function (child) {
            if (child.type !== 'group') {
                child.setStyle('opacity', opacity);
            }
        });
    }

    function fadeInItem(item, opacityPath) {
        var opacity = getItemOpacity(item, opacityPath);
        var el = item.getGraphicEl();

        el.highlight && el.highlight();
        el.traverse(function (child) {
            if (child.type !== 'group') {
                child.setStyle('opacity', opacity);
            }
        });
    }

L
lang 已提交
50 51 52 53
    require('../../echarts').extendChartView({

        type: 'graph',

L
lang 已提交
54
        init: function (ecModel, api) {
L
lang 已提交
55
            var symbolDraw = new SymbolDraw();
L
lang 已提交
56
            var lineDraw = new LineDraw();
L
lang 已提交
57
            var group = this.group;
L
lang 已提交
58

P
pah100 已提交
59 60
            this._controller = new RoamController(api.getZr());
            this._controllerHost = {target: group};
L
lang 已提交
61

L
lang 已提交
62 63
            group.add(symbolDraw.group);
            group.add(lineDraw.group);
L
lang 已提交
64

L
lang 已提交
65
            this._symbolDraw = symbolDraw;
L
lang 已提交
66
            this._lineDraw = lineDraw;
L
lang 已提交
67 68

            this._firstRender = true;
L
lang 已提交
69 70 71
        },

        render: function (seriesModel, ecModel, api) {
L
lang 已提交
72 73 74
            var coordSys = seriesModel.coordinateSystem;

            this._model = seriesModel;
75
            this._nodeScaleRatio = seriesModel.get('nodeScaleRatio');
L
lang 已提交
76

L
lang 已提交
77 78 79
            var symbolDraw = this._symbolDraw;
            var lineDraw = this._lineDraw;

L
lang 已提交
80
            var group = this.group;
81 82 83 84 85 86 87 88 89 90 91 92

            if (coordSys.type === 'view') {
                var groupNewProp = {
                    position: coordSys.position,
                    scale: coordSys.scale
                };
                if (this._firstRender) {
                    group.attr(groupNewProp);
                }
                else {
                    graphic.updateProps(group, groupNewProp, seriesModel);
                }
L
lang 已提交
93
            }
94 95
            // Fix edge contact point with node
            adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));
L
lang 已提交
96

97 98 99 100 101
            var data = seriesModel.getData();
            symbolDraw.updateData(data);

            var edgeData = seriesModel.getEdgeData();
            lineDraw.updateData(edgeData);
L
lang 已提交
102 103 104

            this._updateNodeAndLinkScale();

105
            this._updateController(seriesModel, ecModel, api);
L
lang 已提交
106

L
lang 已提交
107
            clearTimeout(this._layoutTimeout);
L
lang 已提交
108
            var forceLayout = seriesModel.forceLayout;
L
lang 已提交
109
            var layoutAnimation = seriesModel.get('force.layoutAnimation');
L
lang 已提交
110
            if (forceLayout) {
L
lang 已提交
111
                this._startForceLayoutIteration(forceLayout, layoutAnimation);
L
lang 已提交
112
            }
113

L
lang 已提交
114
            data.eachItemGraphicEl(function (el, idx) {
L
lang 已提交
115 116 117
                var itemModel = data.getItemModel(idx);
                // Update draggable
                el.off('drag').off('dragend');
L
lang 已提交
118
                var draggable = data.getItemModel(idx).get('draggable');
119
                if (draggable) {
L
lang 已提交
120
                    el.on('drag', function () {
121 122 123 124 125 126 127 128
                        if (forceLayout) {
                            forceLayout.warmUp();
                            !this._layouting
                                && this._startForceLayoutIteration(forceLayout, layoutAnimation);
                            forceLayout.setFixed(idx);
                            // Write position back to layout
                            data.setItemLayout(idx, el.position);
                        }
L
lang 已提交
129
                    }, this).on('dragend', function () {
130 131 132
                        if (forceLayout) {
                            forceLayout.setUnfixed(idx);
                        }
L
lang 已提交
133
                    }, this);
L
lang 已提交
134
                }
135
                el.setDraggable(draggable && forceLayout);
L
lang 已提交
136

1
100pah 已提交
137 138 139
                el.off('mouseover', el.__focusNodeAdjacency);
                el.off('mouseout', el.__unfocusNodeAdjacency);

L
lang 已提交
140
                if (itemModel.get('focusNodeAdjacency')) {
1
100pah 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153
                    el.on('mouseover', el.__focusNodeAdjacency = function () {
                        api.dispatchAction({
                            type: 'focusNodeAdjacency',
                            seriesId: seriesModel.id,
                            dataIndex: el.dataIndex
                        });
                    });
                    el.on('mouseout', el.__unfocusNodeAdjacency = function () {
                        api.dispatchAction({
                            type: 'unfocusNodeAdjacency',
                            seriesId: seriesModel.id
                        });
                    });
154

L
lang 已提交
155
                }
1
100pah 已提交
156

L
lang 已提交
157
            }, this);
L
lang 已提交
158

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
            data.graph.eachEdge(function (edge) {
                var el = edge.getGraphicEl();

                el.off('mouseover', el.__focusNodeAdjacency);
                el.off('mouseout', el.__unfocusNodeAdjacency);

                if (edge.getModel().get('focusNodeAdjacency')) {
                    el.on('mouseover', el.__focusNodeAdjacency = function () {
                        api.dispatchAction({
                            type: 'focusNodeAdjacency',
                            seriesId: seriesModel.id,
                            edgeDataIndex: edge.dataIndex
                        });
                    });
                    el.on('mouseout', el.__unfocusNodeAdjacency = function () {
                        api.dispatchAction({
                            type: 'unfocusNodeAdjacency',
                            seriesId: seriesModel.id
                        });
                    });
                }
            });

P
pah100 已提交
182 183
            var circularRotateLabel = seriesModel.get('layout') === 'circular'
                && seriesModel.get('circular.rotateLabel');
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
            var cx = data.getLayout('cx');
            var cy = data.getLayout('cy');
            data.eachItemGraphicEl(function (el, idx) {
                var symbolPath = el.getSymbolPath();
                if (circularRotateLabel) {
                    var pos = data.getItemLayout(idx);
                    var rad = Math.atan2(pos[1] - cy, pos[0] - cx);
                    if (rad < 0) {
                        rad = Math.PI * 2 + rad;
                    }
                    var isLeft = pos[0] < cx;
                    if (isLeft) {
                        rad = rad - Math.PI;
                    }
                    var textPosition = isLeft ? 'left' : 'right';
                    symbolPath.setStyle({
P
tweak  
pah100 已提交
200
                        textRotation: -rad,
P
pah100 已提交
201 202
                        textPosition: textPosition,
                        textOrigin: 'center'
203 204 205 206 207 208 209 210 211 212
                    });
                    symbolPath.hoverStyle && (symbolPath.hoverStyle.textPosition = textPosition);
                }
                else {
                    symbolPath.setStyle({
                        textRotation: 0
                    });
                }
            });

L
lang 已提交
213
            this._firstRender = false;
L
lang 已提交
214 215
        },

1
100pah 已提交
216 217
        dispose: function () {
            this._controller && this._controller.dispose();
P
pah100 已提交
218
            this._controllerHost = {};
1
100pah 已提交
219 220
        },

1
100pah 已提交
221
        focusNodeAdjacency: function (seriesModel, ecModel, api, payload) {
L
lang 已提交
222
            var data = this._model.getData();
223
            var graph = data.graph;
1
100pah 已提交
224
            var dataIndex = payload.dataIndex;
225 226 227 228
            var edgeDataIndex = payload.edgeDataIndex;

            var node = graph.getNodeByIndex(dataIndex);
            var edge = graph.getEdgeByIndex(edgeDataIndex);
1
100pah 已提交
229

230
            if (!node && !edge) {
1
100pah 已提交
231 232 233
                return;
            }

234 235 236 237 238 239
            graph.eachNode(function (node) {
                fadeOutItem(node, nodeOpacityPath, 0.1);
            });
            graph.eachEdge(function (edge) {
                fadeOutItem(edge, lineOpacityPath, 0.1);
            });
L
lang 已提交
240

241
            if (node) {
L
lang 已提交
242
                fadeInItem(node, nodeOpacityPath);
243 244
                zrUtil.each(node.edges, function (adjacentEdge) {
                    if (adjacentEdge.dataIndex < 0) {
L
lang 已提交
245 246
                        return;
                    }
247 248 249
                    fadeInItem(adjacentEdge, lineOpacityPath);
                    fadeInItem(adjacentEdge.node1, nodeOpacityPath);
                    fadeInItem(adjacentEdge.node2, nodeOpacityPath);
L
lang 已提交
250 251
                });
            }
252 253 254 255 256
            if (edge) {
                fadeInItem(edge, lineOpacityPath);
                fadeInItem(edge.node1, nodeOpacityPath);
                fadeInItem(edge.node2, nodeOpacityPath);
            }
L
lang 已提交
257 258
        },

1
100pah 已提交
259 260
        unfocusNodeAdjacency: function (seriesModel, ecModel, api, payload) {
            var graph = this._model.getData().graph;
261

L
lang 已提交
262
            graph.eachNode(function (node) {
263
                fadeOutItem(node, nodeOpacityPath);
L
lang 已提交
264 265
            });
            graph.eachEdge(function (edge) {
266
                fadeOutItem(edge, lineOpacityPath);
L
lang 已提交
267 268 269
            });
        },

L
lang 已提交
270
        _startForceLayoutIteration: function (forceLayout, layoutAnimation) {
L
lang 已提交
271 272 273
            var self = this;
            (function step() {
                forceLayout.step(function (stopped) {
274
                    self.updateLayout(self._model);
L
lang 已提交
275
                    (self._layouting = !stopped) && (
L
lang 已提交
276 277 278 279
                        layoutAnimation
                            ? (self._layoutTimeout = setTimeout(step, 16))
                            : step()
                    );
L
lang 已提交
280 281
                });
            })();
L
lang 已提交
282 283
        },

284
        _updateController: function (seriesModel, ecModel, api) {
L
lang 已提交
285
            var controller = this._controller;
P
pah100 已提交
286
            var controllerHost = this._controllerHost;
287
            var group = this.group;
288

289
            controller.setPointerChecker(function (e, x, y) {
290 291
                var rect = group.getBoundingRect();
                rect.applyTransform(group.transform);
292 293
                return rect.contain(x, y)
                    && !cursorHelper.onIrrelevantElement(e, api, seriesModel);
294 295
            });

296 297 298 299
            if (seriesModel.coordinateSystem.type !== 'view') {
                controller.disable();
                return;
            }
L
lang 已提交
300
            controller.enable(seriesModel.get('roam'));
P
pah100 已提交
301 302
            controllerHost.zoomLimit = seriesModel.get('scaleLimit');
            controllerHost.zoom = seriesModel.coordinateSystem.getZoom();
L
lang 已提交
303 304 305 306 307

            controller
                .off('pan')
                .off('zoom')
                .on('pan', function (dx, dy) {
P
pah100 已提交
308
                    roamHelper.updateViewOnPan(controllerHost, dx, dy);
L
lang 已提交
309
                    api.dispatchAction({
P
pah100 已提交
310
                        seriesId: seriesModel.id,
L
lang 已提交
311 312 313 314 315 316
                        type: 'graphRoam',
                        dx: dx,
                        dy: dy
                    });
                })
                .on('zoom', function (zoom, mouseX, mouseY) {
P
pah100 已提交
317
                    roamHelper.updateViewOnZoom(controllerHost, zoom, mouseX, mouseY);
L
lang 已提交
318
                    api.dispatchAction({
P
pah100 已提交
319
                        seriesId: seriesModel.id,
L
lang 已提交
320 321 322 323 324
                        type: 'graphRoam',
                        zoom:  zoom,
                        originX: mouseX,
                        originY: mouseY
                    });
325 326 327 328
                    this._updateNodeAndLinkScale();
                    adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));
                    this._lineDraw.updateLayout();
                }, this);
L
lang 已提交
329 330 331 332 333
        },

        _updateNodeAndLinkScale: function () {
            var seriesModel = this._model;
            var data = seriesModel.getData();
334 335 336 337 338 339 340 341 342 343

            var nodeScale = this._getNodeGlobalScale(seriesModel);
            var invScale = [nodeScale, nodeScale];

            data.eachItemGraphicEl(function (el, idx) {
                el.attr('scale', invScale);
            });
        },

        _getNodeGlobalScale: function (seriesModel) {
344
            var coordSys = seriesModel.coordinateSystem;
345 346 347
            if (coordSys.type !== 'view') {
                return 1;
            }
L
lang 已提交
348 349 350

            var nodeScaleRatio = this._nodeScaleRatio;

L
lang 已提交
351
            var groupScale = coordSys.scale;
352 353 354 355
            var groupZoom = (groupScale && groupScale[0]) || 1;
            // Scale node when zoom changes
            var roamZoom = coordSys.getZoom();
            var nodeScale = (roamZoom - 1) * nodeScaleRatio + 1;
L
lang 已提交
356

357
            return nodeScale / groupZoom;
L
lang 已提交
358 359
        },

360
        updateLayout: function (seriesModel) {
L
lang 已提交
361 362
            adjustEdge(seriesModel.getGraph(), this._getNodeGlobalScale(seriesModel));

L
lang 已提交
363 364 365
            this._symbolDraw.updateLayout();
            this._lineDraw.updateLayout();
        },
L
lang 已提交
366

L
lang 已提交
367
        remove: function (ecModel, api) {
L
lang 已提交
368 369
            this._symbolDraw && this._symbolDraw.remove();
            this._lineDraw && this._lineDraw.remove();
L
lang 已提交
370 371 372
        }
    });
});