发表于 & 归档在 HTML5, JavaScript, 案例.

多位客户提到编辑器的需求,譬如拖拽创建节点,文本编辑,连线编辑,尺寸编辑等等,编辑是一个系列话题,将陆续作介绍,本章介绍拖拽创建节点与简单的连线编辑交互

拖拽创建节点

拖拽创建节点,以前要实现拖拽,需要监听全局mousemove事件,复制拖拽元素,实现drop效果,现在HTML5提供了新的拖拽事件,处理起来变得很容易

创建画布面板canvas,并在左侧创建一个工具箱toolbox,设置canvas监听drop和dragover事件,工具箱中的图片监听dragstart事件,并设置为可拖拽

<div id="canvas" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<div id="toolbox">
<img src="node_icon.png" title="拖拽创建节点" draggable="true" ondragstart="drag(event)" image="node" type="Node" label="Node" />
</div>

拖拽事件处理

按如下方式处理拖拽事件,通过dataTransfer传递拖拽数据,并在drop时,创建新的节点

function allowDrop(ev) {
    ev.preventDefault();
}

function drag(ev) {
    ev.dataTransfer.setData("image", ev.target.getAttribute("image"));
    ev.dataTransfer.setData("type", ev.target.getAttribute("type"));
    ev.dataTransfer.setData("label", ev.target.getAttribute("label"));
}

function drop(ev) {
    ev.preventDefault();
    var image = ev.dataTransfer.getData("image");
    var type = ev.dataTransfer.getData("type");
    var label = ev.dataTransfer.getData("label");

    var xy = graph.globalToLocal(ev);
    xy = graph.toLogical(xy.x, xy.y);

    if(type == "Node"){
        var node = graph.createNode(label, xy.x, xy.y);
        if(image){
            if(image.indexOf(".") < 0){
                image = Q.Graphs[image];
            }
            node.image = image;
        }
    }
}

注意鼠标事件转换成Qunee逻辑坐标的代码:
var xy = graph.globalToLocal(ev);//鼠标事件转换成组件坐标
xy = graph.toLogical(xy.x, xy.y);//转换成逻辑坐标

创建连线交互

创建连线交互需要扩展交互模式,监听Qunee组件提供的drag监听,实现鼠标拖拽创建连线功能,并在交互画布上绘制连线轨迹

新建交互类CreateEdgeInteraction,并通过Q.Defaults.registerInteractions注册新的交互模式

var CREATE_EDGE_MODE = "create.edge.mode";
function CreateEdgeInteraction(graph){
    this.graph = graph;
    this.topCavans = graph.topCanvas;

}
CreateEdgeInteraction.prototype = {
    destroy: function(graph){
        this.start = null;
        graph.cursor = null;
        if(this.drawLineId){
            this.topCavans.removeDrawable(this.drawLineId);
            delete this.drawLineId;
            this.topCavans.invalidate();
        }
    },
    drawLine: function(g, scale){
        var x = this.start.x;
        var y = this.start.y;
        g.moveTo(x, y);
        if(this.edgeClass == FlexEdgeUI){
            var cx = (this.start.x + this.end.x) / 2;
            var cy = (this.start.y + this.end.y) / 2;
            g.bezierCurveTo(this.start.x, this.start.y, cx, this.end.y, this.end.x, this.end.y);
        }else{
            g.lineTo(this.end.x, this.end.y);
        }
        g.lineWidth = 3;
        g.strokeStyle = "#88F";
        g.stroke();
    },
    invalidate: function(){
        this.topCavans.invalidate();
    },
    startdrag: function(evt, graph){
        var start = evt.getData();
        if(!(start instanceof Q.Node)){
            return;
        }
        evt.responded = true;
        this.start = start;
        graph.cursor = "crosshair";
        this.drawLineId = this.topCavans.addDrawable(this.drawLine, this).id;
    },
    ondrag: function(evt, graph){
        if(!this.start){
            return;
        }
        Q.stopEvent(evt);
        this.end = graph.getLogicalPointByMouseEvent(evt);
        this.invalidate();
    },
//    edgeClass: FlexEdgeUI,
    enddrag: function(evt, graph){
        if(!this.start){
            return;
        }
        graph.cursor = "";
        this.invalidate();
        var end = graph.getElementByMouseEvent(evt);
        if(end){
            var edge = graph.createEdge(this.start, end);
            if(this.edgeClass){
                edge.uiClass = this.edgeClass;
            }
        }
        this.destroy(graph);
    }
}
Q.Defaults.registerInteractions(CREATE_EDGE_MODE, [CreateEdgeInteraction, Q.PanInteraction]);

使用交互模式

增加一个切换按钮,实现默认交互模式与创建连线模式的切换

<img style="cursor: pointer;" title="创建连线" onclick="onCreateEdgeButtonClick(event)" alt="" src="edge_icon.png" />

切换交互模式

function onCreateEdgeButtonClick(evt){
    var target = evt.target;
    if(target.selected){
        target.selected = false;
        target.className = "";
    }else{
        target.selected = true;
        target.className = "selected";
    }
    graph.interactionMode = target.selected ? CREATE_EDGE_MODE : Q.Consts.INTERACTION_MODE_DEFAULT;
}

运行效果

创建连线交互

 

在线演示

http://demo.qunee.com/editor/Editor.html

13 回复 给 “拓扑图编辑器(1)”

      • 微笑

        有一个问题想咨询下,graph的创建位置应该放在哪里?我放到drop()函数中,结果是只能拖拽一个组件;如果放到函数外作为全局变量,结果是创建的graph大小为0,虽然可以拖拽两次,但无法呈现在画布上。请问,graph应该放在什么地方进行创建?
        谢谢!

        回复
        • sam

          可以在dom加载完成后初始化graph,如果你使用jquery的话,可以用下面的代码
          var graph;
          $(function(){
          graph = new Q.Graph(...);
          ...
          })

          回复
  1. 微笑

    这样虽然可以生成不为0的graph的画布,但是没有办法拖拽组件。下面是代码,您帮忙看下问题在哪儿?

    拓扑编辑器

    var graph;
    function init(){
    graph = new Q.Graph(“canvas”);
    alert(” graph.width = ” + graph.width);
    }
    // var graph = new Q.Graph(“canvas”);
    // alert(” graph.width = ” + graph.width);

    function allowDrop(ev) {
    ev.preventDefault();
    }

    function drag(ev) {
    ev.dataTransfer.setData(“type”, ev.target.getAttribute(“type”));
    ev.dataTransfer.setData(“label”, ev.target.getAttribute(“label”));
    ev.dataTransfer.setData(“src”, ev.target.getAttribute(“src”));
    }

    function drop(ev) {
    ev.preventDefault();
    var type = ev.dataTransfer.getData(“type”);
    var label = ev.dataTransfer.getData(“label”);
    var src = ev.dataTransfer.getData(“src”);

    // graph = new Q.Graph(“canvas”);
    // alert(graph.width);
    var xy = graph.globalToLocal(ev);
    xy = graph.toLogical(xy.x, xy.y);

    if(type == “Node”){
    var node = graph.createNode(null,xy.x – graph.width / 2, xy.y – graph.height / 2);
    if(src){
    node.image = src;
    }
    }

    }

    回复
  2. 微笑

    这样的结果是:当拖拽组件时,组件不会被拖拽到canvas中,而是在一个独立页面中以图片的形式显示出来。就像http://demo.qunee.com/editor/Editor.html示例中一样,不同的是示例中是以一个新的页面呈现,在我本地是直接替换了原页面。

    回复
  3. hhfwn

    你好,qunee在拖拽一段时间后,就会出现 qunee for html5,无法编辑或者选中。请问这是什么问题呢

    回复
    • admin

      license问题,试用版本仅限本机(localhost, 127.0.0,1)发布使用,请购买正式授权给,非商业用途授权请申请免费授权

      回复

Trackbacks/Pingbacks

  1.  拓扑图编辑器(2) | Qunee技术博客
  2.  拓扑图编辑器(3)- Graph.Editor项目 | Qunee技术博客

发表评论

电子邮件地址不会被公开。 必填项已用*标注


− 三 = 2

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>