0

I am new to zoom charts (net charts) and I have a couple of questions:

  • I would like to be able to drag a node and when the user drops it, to process the event. Is there a way to do that? I was looking at the onPositionChange event, but that event fires multiple times during the drag. There is no way to know when the user actually dropped the node. At least I did not find a way to determine that. Maybe I am missing something.
  • I have a list of items that I want to be able to drag into the chart and convert them into Nodes. This works fine except that when I consume the dragend (of the external item) event I cannot properly set the x and y positioning of the newly created Node. I tried using ClientX and ClientY, LayerX and LayerY, and the other coordinates provided by the DragEnd event args, but none of them positions the Node where the cursor was released. What is the best way to accomplish this?

Here is my chart definition:

this.chart = new ZoomCharts.NetChart({
   container: chartContainer,
   area: {
    height: null,
    style: { fillColor: "rgba(14,33,40,0.9)" }
   },
   data: {
    preloaded: {
     "nodes": this.nodes,
     "links": this.links
    }
   },
   events: {
    onRightClick: function (event: any, args: any) {
     //set up the customer context menu
     event.preventDefault();
    },
    onHoverChange: function (event: any, args: any) {
     var content = "";
     if (args.hoverNode) {
      content = args.hoverNode.data.description;
     }
     infoElementVisible = !!content;
     infoElement.innerHTML = content;
     //delay the showing
     if (infoElementVisible) {
      setTimeout(() => {
       infoElement.style.display = infoElementVisible ? "block" : "none";
      }, 1000);
     } else {
      infoElement.style.display = infoElementVisible ? "block" : "none";
     }   
    }
   },
   style: {
    nodeStyleFunction: function (node: any) {
     if (node.selected) {
      node.lineColor = "yellow";
      node.lineWidth = 3;
      node.radius = node.radius * 1.5;
     } else {
      node.lineColor = null;
      node.lineWidth = 0;
     }

     node.userLock = true;
     node.label = node.data.name;
     if (node.data.auras == "Selection GNQ") {
      node.fillColor = "darkorange";
     } else {
      node.fillColor = "cyan";
     }
    },
    linkStyleFunction: function (link: any) {
     link.fromDecoration = "circle";
     link.toDecoration = "arrow";
     link.radius = 5;
    },
    node: {
     radius: 50,
     imageCropping: true,
     shadowBlur: 15,
     shadowColor: "#262626",
     fillColor: "rgba(44,233,233,0.8)"
    },
    nodeHovered: {
     shadowColor: "white",
     shadowBlur: 15,
    },
    nodeLabelScaleBase: 25,
    nodeSelected: {
     lineColor: null
    },
    selection: {
     fillColor: null,
     lineColor: null
    },
    nodeFocused: {
     shadowColor: "yellow",
     shadowBlur: 15
    },
    nodeLabel: {
     textStyle: { font: '24px Arial' }
    }
   },
   theme: ZoomCharts.NetChart.themes.dark,
   layout: {
    mode: 'static',
    nodeSpacing: 100
   }
  });

Thank you.

dpdragnev
  • 2,011
  • 2
  • 28
  • 55

2 Answers2

1

Hi @dpdragnev! I'm from ZoomCharts, so this is kind of an authoritative answer. :)

  1. Yes, you're right, we don't have a way of telling that. Hmm... I can think of one hack to get there, but I've never tried that before, so... Attach event handlers to the container element of NetChart. Attach them to pointerup, pointercancel, mouseup, touchend, touchcancel, MSPointerUp, MSPointerCancel. These are all events that will interrupt a drag operation. You'll probably need to check which ones are available too and only attach to those. You need to attach to the capture phase, because NetChart will prevent bubbling. Then also attach to the onPositionChange event of NetChart to see when a node drag is starting. In the onPositoinChange event check the identifier field of the mouse event. That will tell you which pointer is the one dragging (important for multi-touch support). So now you have an event when a node is being dragged, and an event when a node is being released, and the pointer identifier to match them up. Should work, I think.
  2. Again, no good way, sorry. But there's a hack we've used ourselves. By looking at the ._impl.scene.centerX and ._impl.scene.centerY properties of your NetChart object you can get the x/y coordinates of the center of the chart in scene coordinates. Zoom can be obtained perfectly legally with a .zoom() API call. Add some math and you can figure out the scene coordinates of your mouse cursor. Put your node there. Note that this is NOT a documented approach and can stop working at any time. Use at your own risk.
Community
  • 1
  • 1
Vilx-
  • 104,512
  • 87
  • 279
  • 422
0

ZoomCharts introduced new events for NetChart with 1.18.0 (2017-10-05) release. All the events can be found here.

Here I have prepared a quick example where it is possible to drag and drop a node over the other nodes. In this case it would create a link between nodes with direction.

http://jsfiddle.net/cmx907hp/

Code:

var ndata = {
        "nodes":[
            {"id":"n1", "loaded":true, "style":{"label":"Node1", "fillColor":"rgba(236,46,46,0.8)"}, "x":0, "y":0, "locked": true},
            {"id":"n2", "loaded":true, "style":{"label":"Node2", "fillColor":"rgba(47,195,47,0.8)" }, "x":200, "y":50},
            {"id":"n3", "loaded":true, "style":{"labeL":"Node3", "fillColor":"rgba(28,124,213,0.8)" }, "x":100, "y":100},
            {"id":"n4", "loaded":true, "style":{"labeL":"Node4", "fillColor":"rgba(236,46,46,1)" }, "x":250, "y":250, "locked": true}
        ],
        "links":[
            {"id":"l1","from":"n1", "to":"n2"}
        ]
    };



    var chart = new NetChart({
        container: document.getElementById("demo"),
        area: { height: $(window).height() - 120 },
        data: { preloaded: ndata },
        events: {
            onClick: function(e, args) {
                console.log("click", args);
            },
            onPointerDown: function(e, args) {
                console.log("down", args);
            },
            onPointerUp: function(e, args) {
                console.log("up", args);
                if(args.clickNode) {
                    var node = args.clickNode;
                    var onodes = getOverlappingNodes(node);
                    connectNodes(node, onodes);
                }
            },
            onPointerDrag: function(e, args) {
                console.log("drag", args);
            },
            onPointerMove: function(e, args) {
                //this is basically onMouseMove, but originally was named like this.
            }
        },
        navigation: {
          //  mode: "showall"
        }
    });


    function getOverlappingNodes(node) {
    if(!node) return;

    var found = [];
    var dim = chart.getNodeDimensions(node);

    var x = x1 = dim.x;
    var y = y1 = dim.y;
    var radius = dim.radius;

    //get all nodes:
    var nodes = chart.nodes();
    for (var i = 0; i < nodes.length; i++) {
        var obj = nodes[i];
        //skip dragged node itself.
        if(obj.id === node.id) {
            continue;
        }
        var odim = chart.getNodeDimensions(obj);
        var x0 = odim.x;
        var y0 = odim.y;

        var m = Math.sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)) < radius;
        if(m) {
            found.push(obj);
        }
    }
    return found;
}


function connectNodes(node, onodes) {
    for (var i = 0; i < onodes.length; i++) {
        var onode = onodes[i];

        var link = {"id": "link-" + node.id + "-" + onode.id,"from": node.id, "to": onode.id, style: {"toDecoration": "arrow"}}
        chart.addData({nodes:[],links: [link]});
    }
}
Eizens
  • 46
  • 3