图表创建者使用KineticJS

时间:2013-09-09 19:33:14

标签: javascript html5 css3 kineticjs diagramming

我正在使用KineticJS编写一个简单的图表编辑器。我想为调色板区域使用两个单独的画布(包含许多表示我可能创建的网络的不同节点的Kinetic.Groups),以及可以通过拖放从调色板添加节​​点的图表区域,然后在各个节点之间添加连接作为特定锚点。我很难搞清楚从(静止的)Kinetic.Groups的调色板画布到包含图表区域的其他画布的拖放过程。我猜我需要触发调色板对象的dragstart事件(尽管我不希望这些事件可以拖动),然后做一些像创建可以拖动的调色板对象的opague副本,最后进入图表区域(完全不透明)。

可以将群组拖到暂存画布边界之外吗?当我开始从调色板拖动时,我需要生成一个图像,拖动该图像,然后在放入图表区域时创建另一个组。

是否有人知道任何可能指向正确方向的示例,或者谁可以为所需流程提供一些见解(甚至是代码)。我已经搜索了KineticJS的例子,但是找不到足够的信息让我离开。

1 个答案:

答案 0 :(得分:1)

以下是将节点从源面板拖动到目标组的一种方法:

小提琴:http://jsfiddle.net/m1erickson/xtVyL/

enter image description here

网络节点由小图标(实际上是小型动态图像对象)表示。

用户可以将任何图标从源面板拖动到任何目标组。

这些组只是画布上定义的区域,但可以是Kinetc.Groups以获得更大的灵活性。

在dragend事件期间,将在目标组中创建拖动图标的新副本。

dragend事件完成后,将自动移动原始调色板图标 可以在目标组周围拖动新创建的重复图标(但不能在该组外部)。

这是代码和小提琴:http://jsfiddle.net/m1erickson/xtVyL/

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Prototype</title>
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.5.min.js"></script>

<style>
#container{
  border:solid 1px #ccc;
  margin-top: 10px;
  width:350px;
  height:350px;
}
</style>        
<script>
$(function(){

    var stage = new Kinetic.Stage({
        container: 'container',
        width: 350,
        height: 350
    });
    var layer = new Kinetic.Layer();
    stage.add(layer);


    // image loader

    var imageURLs=[];
    var imagesOK=0;
    var imgs=[];
    imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tempPC.png");
    imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tempServer.png");
    imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tempRouter.png");
    loadAllImages();

    function loadAllImages(callback){
        for (var i = 0; i < imageURLs.length; i++) {
            var img = new Image();
            imgs.push(img);
            img.onload = function(){ 
                imagesOK++; 
                if (imagesOK==imageURLs.length ) {
                    start();
                }
            }; 
            img.src = imageURLs[i];
        }      
    }


    // top icon positions
    var nextIconX=20;
    var nextIconY=20;

    // define groups
    var groups=[];
    groups.push({x:0,y:100,w:175,h:250,fill:"skyblue"});
    groups.push({x:175,y:100,w:175,h:250,fill:"cornsilk"});
    // add boundary info to each group
    // draw colored rect to show group area
    for(var i=0;i<groups.length;i++){
        var g=groups[i];
        g.left=g.x;
        g.right=g.x+g.w;
        g.top=g.y;
        g.bottom=g.y+g.h;
        var rect=new Kinetic.Rect({
            x:g.x,
            y:g.y,
            width:g.w,
            height:g.h,
            fill:g.fill,
            stroke:"gray"
        });
        layer.add(rect);
    }
    // hittest for each group
    function groupHit(x,y){
        for(var i=0;i<groups.length;i++){
            var g=groups[i];
            if(x>g.left && x<g.right && y>g.top && y<g.bottom){return(i);}
        }
        return(-1);
    }


    function start(){
        makePaletteIcon(imgs[0]);
        makePaletteIcon(imgs[1]);
        makePaletteIcon(imgs[2]);
        layer.draw();
    }


    function makePaletteIcon(img){

        // make an icon that stays in the pallette tray
        var fixedIcon=newImage(nextIconX,nextIconY,img,false);
        layer.add(fixedIcon);


        // make an icon that is dragged from the tray to a group
        var dragIcon=makeDraggableIcon(nextIconX,nextIconY,img);
        layer.add(dragIcon);

        // calc the next icon position
        nextIconX+=(img.width+20);

    }


    function makeDraggableIcon(x,y,img){

        var i=newImage(x,y,img,true);
        // 
        i.trayX=x;
        i.trayY=y;
        //
        i.setOpacity(0.50);

        i.on("dragend",function(){

            var x=this.getX();
            var y=this.getY();

            // if this pallette icon was not dropped in a group
            // put the icon back in the tray and return
            var hit=groupHit(x,y);
            if(hit==-1){
                this.setPosition(this.trayX,this.trayY);
                return;
            }

            // add a copy of this icon to the drop group  
            var component=newImage(x,y,this.getImage(),true);

            // set drag limits
            var group=groups[hit];
            component.maxDragLeft=group.left;
            component.maxDragRight=group.right;
            component.maxDragTop=group.top;
            component.maxDragBottom=group.bottom;

            // limit component dragging to inside the assigned group
            component.setDragBoundFunc(function(pos) {
                var xx=pos.x;
                var yy=pos.y;
                var w=this.getWidth();
                var h=this.getHeight();
                if(pos.x<this.maxDragLeft){xx=this.maxDragLeft;}
                if(pos.x+w>this.maxDragRight){xx=this.maxDragRight-w;}
                if(pos.y<this.maxDragTop){yy=this.maxDragTop;}
                if(pos.y+h>this.maxDragBottom){yy=this.maxDragBottom-h;}
                return{ x:xx, y:yy };
            });

            layer.add(component);

            // move the dragIcon back into the pallette tray
            this.setPosition(this.trayX,this.trayY);

            layer.draw();

        });

        return(i);
    }

    // make a new Kinetic.Image
    function newImage(x,y,img,isDraggable){
        var i=new Kinetic.Image({
            image:img,
            x: x,
            y: y,
            width: img.width,
            height: img.height,
            draggable:isDraggable
        });
        return(i);
    }


}); // end $(function(){});

</script>       
</head>

<body>
    <p>Drag any icon from top into blue or yellow group</p>
    <div id="container"></div>
</body>
</html>