Apply onmouseover on each node - GOjs library - swimlane

社会主义新天地 提交于 2019-12-13 00:55:24

问题


I've done the first part, adding colors on each node. The next step would be how to add onmouseover on each node then highlight/apply style on the subgraph (including the links/lines connecting it) belonging to the hovered node.

Anyone knows?

This is my code so far:

        <?php
    $prospectus = array(
    'subjects' => array(
        'First Year' => array(
            array('course_no' => 'CS 110'       , 'color' => '#21ff1c'),
            array('course_no' => 'CS 111'       , 'color' => 'white'),
            array('course_no' => 'MATH 1'       , 'color' => 'white'),
            array('course_no' => 'MATH 2'       , 'color' => 'white'),
            array('course_no' => 'ENGL 1'       , 'color' => 'white'),
            array('course_no' => 'REED 1'       , 'color' => 'white'),
            array('course_no' => 'PE 1'         , 'color' => 'white'),
            array('course_no' => 'CWTS/ROTC 11' , 'color' => 'white'),
            array('course_no' => 'GUIDANCE 1'   , 'color' => 'white'),
            array('course_no' => 'CS 120'       , 'color' => 'white'),
            array('course_no' => 'CS 121'       , 'color' => 'white'),
            array('course_no' => 'CS 122'       , 'color' => 'white'),
            array('course_no' => 'MATH 4'       , 'color' => 'white'),
            array('course_no' => 'ENGL 2'       , 'color' => 'white'),
            array('course_no' => 'REED 2'       , 'color' => 'white'),
            array('course_no' => 'PE 2'         , 'color' => 'white'),
            array('course_no' => 'CWTS/ROTC 12' , 'color' => 'white'),
            array('course_no' => 'GUIDANCE 2'   , 'color' => 'white')
        ),
        'Second Year' => array(
            array('course_no' => 'CS 211'       , 'color' => 'white'),
            array('course_no' => 'CS 212'       , 'color' => 'white'),
            array('course_no' => 'CS 213'       , 'color' => 'white'),
            array('course_no' => 'ENGL 3'       , 'color' => 'white'),
            array('course_no' => 'MATH 6'       , 'color' => 'white'),
            array('course_no' => 'REED 3'       , 'color' => 'white'),
            array('course_no' => 'PE 3'         , 'color' => 'white'),
            array('course_no' => 'CS 221'       , 'color' => 'white'),
            array('course_no' => 'CS 222'       , 'color' => 'white'),
            array('course_no' => 'CS 223'       , 'color' => 'white'),
            array('course_no' => 'CS 224'       , 'color' => 'white'),
            array('course_no' => 'ENGL 4'       , 'color' => 'white'),
            array('course_no' => 'REED 4'       , 'color' => 'white'),
            array('course_no' => 'PE 4'         , 'color' => 'white'),
            array('course_no' => 'HUMANITIES 1' , 'color' => 'white'),
            array('course_no' => 'MATH 7'       , 'color' => 'white')
        )
    ),
    'preqs'    => array(
        array('subject' => 'CS 120'      , 'preq' => 'CS 110'),
        array('subject' => 'CS 121'      , 'preq' => 'CS 111'),
        array('subject' => 'CS 122'      , 'preq' => 'MATH 1'),
        array('subject' => 'MATH 4'      , 'preq' => 'MATH 1'),
        array('subject' => 'MATH 4'      , 'preq' => 'MATH 2'),
        array('subject' => 'ENGL 2'      , 'preq' => 'ENGL 1'),
        array('subject' => 'REED 2'      , 'preq' => 'REED 1'),
        array('subject' => 'PE 2'        , 'preq' => 'PE 1'  ),
        array('subject' => 'CWTS/ROTC 12', 'preq' => 'CWTS/ROTC 11'),
        array('subject' => 'GUIDANCE 2'  , 'preq' => 'GUIDANCE 1'),

        array('subject' => 'CS 211'        , 'preq' => 'CS 121'),
        array('subject' => 'CS 212'        , 'preq' => 'CS 110'),
        array('subject' => 'CS 213'        , 'preq' => 'CS 122'),
        array('subject' => 'ENGL 3'        , 'preq' => 'ENGL 2'),
        array('subject' => 'MATH 6'        , 'preq' => 'MATH 4'),
        array('subject' => 'REED 3'        , 'preq' => 'REED 2'),
        array('subject' => 'PE 3'          , 'preq' => 'PE 2'),

        array('subject' => 'CS 221'        , 'preq' => 'CS 122'),
        array('subject' => 'CS 221'        , 'preq' => 'CS 211'),
        array('subject' => 'CS 222'        , 'preq' => 'CS 211'),
        array('subject' => 'CS 223'        , 'preq' => 'CS 211'),
        array('subject' => 'CS 224'        , 'preq' => 'CS 121'),
        array('subject' => 'ENGL 4'        , 'preq' => 'ENGL 2'),
        array('subject' => 'REED 4'        , 'preq' => 'REED 3'),
        array('subject' => 'PE 4'          , 'preq' => 'PE 3'),
    )
);
?>

<!DOCTYPE html>
<html>
<head>
<title>Swimlane</title>
<!-- Copyright 1998-2014 by Northwoods Software Corporation. -->
<link href="goSamples.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="go.js"></script>
<script id="code">

function highlightNode(node, color) {
    if (node === null) return;
    var shape = node.findMainElement();
    if (shape === null) return;
    if (color !== undefined) {
        if (!shape.previousStroke) shape.previousStroke = shape.stroke;
        shape.stroke = color;
    } else {  // restore previous color
        shape.stroke = shape.previousStroke;
    }
}

function highlightLink(link, color) {
    if (link === null) return;
    var shape = link.findMainElement();
    if (shape === null) return;
    if (color !== undefined) {
        if (!shape.previousStroke) shape.previousStroke = shape.stroke;
        shape.stroke = color;
    } else {  // restore previous color
        shape.stroke = shape.previousStroke;
    }
}

function highlightConnectedNodes(node, color) {
    if (node === null) return;

    var lit = node.findLinksOutOf();

    while (lit.next()) {
        highlightLink(lit.value, color);
    }

    var nit = node.findNodesOutOf();

    while (nit.next()) {
        highlightNode(nit.value, color);
        highlightConnectedNodes(nit.value, color);
    }
}

// These parameters need to be set before defining the templates.
// this controls whether the swimlanes are horizontal stacked vertically, or the other way:
var HORIZONTAL = false;
// this controls the minimum length of any swimlane
var MINLENGTH = 500;
// this controls the minimum breadth of any swimlane
var MINBREADTH = 360;


// compute the minimum length needed to hold all of the subgraphs
function computeMinPlaceholderSize(diagram) {

    var len = MINLENGTH;

    for (var it = diagram.nodes; it.next(); ) {
        var group = it.value;

        if (!(group instanceof go.Group))
            continue;

        var holder = group.placeholder;

        if (holder !== null) {
            var sz = holder.actualBounds;
            len = Math.max(len, (HORIZONTAL ? sz.width : sz.height));
        }
    }

    return (HORIZONTAL ? new go.Size(len, NaN) : new go.Size(NaN, len));
}

// get the minimum placeholder size for a particular Group;
// when group is null, return the minimum size
function computePlaceholderSize(group) {

    if (group instanceof go.Group) {
        var holder = group.placeholder;

        if (holder !== null) {
            return holder.actualBounds.size;
        }
    }

    return (HORIZONTAL ? new go.Size(MINLENGTH, MINBREADTH) : new go.Size(MINBREADTH, MINLENGTH));
}

// define a custom grid layout that makes sure the length of each lane is the same
// and that each lane is broad enough to hold its subgraph
function StackLayout() {
    go.GridLayout.call(this);
}
go.Diagram.inherit(StackLayout, go.GridLayout);

StackLayout.prototype.doLayout = function(coll) {
    var diagram = this.diagram;

    if (diagram === null)
        return;

    diagram.startTransaction("StackLayout");

    // make sure all of the Group Shapes are big enough
    var minsize = computeMinPlaceholderSize(diagram);

    for (var it = diagram.nodes; it.next(); ) {
        var group = it.value;

        if (!(group instanceof go.Group))
            continue;

        var shape = group.findObject("SHAPE");

        if (shape !== null) {  // change the desiredSize to be big enough in both directions
            var sz = computePlaceholderSize(group);

            if (HORIZONTAL) {
                shape.width = (isNaN(shape.width) ? minsize.width : Math.max(shape.width, minsize.width));

                if (!isNaN(shape.height))
                    shape.height = Math.max(shape.height, sz.height);
            } else {
                if (!isNaN(shape.width))
                    shape.width = Math.max(shape.width, sz.width);
                shape.height = (isNaN(shape.height) ? minsize.height : Math.max(shape.height, minsize.height));
            }

            var cell = group.resizeCellSize;

            if (!isNaN(shape.width) && !isNaN(cell.width) && cell.width > 0)
                shape.width = Math.ceil(shape.width / cell.width) * cell.width;
            if (!isNaN(shape.height) && !isNaN(cell.height) && cell.height > 0)
                shape.height = Math.ceil(shape.height / cell.height) * cell.height;
        }
    }

    // now do all of the usual stuff, according to whatever properties have been set on this GridLayout
    go.GridLayout.prototype.doLayout.call(this, coll);
    diagram.commitTransaction("StackLayout");
};
// end StackLayout class

function init() {

    var $ = go.GraphObject.make;
    myDiagram =
        $(go.Diagram, "myDiagram",
            {
                initialContentAlignment: go.Spot.Center,
                layout:
                    $(StackLayout,
                        {
                            cellSize: new go.Size(1, 1),
                            spacing: new go.Size(0, 0),
                            wrappingColumn: (HORIZONTAL ? 1 : Infinity),
                            wrappingWidth: Infinity,
                            isViewportSized: false
                        })
            });

    myDiagram.nodeTemplate =
        $(go.Node, "Auto",
            $(go.Shape, "Rectangle",
                { fill: "lightblue", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true },
                new go.Binding("fill", "color")),
            $(go.TextBlock, { margin: 5 },
                new go.Binding("text", "key")),
            // limit dragging of Nodes to stay within the containing Group, defined above
            {
                mouseEnter: function(e, obj, prev) {
                    var shape = obj.findMainElement();
                    if (shape){
                        shape.previousFill = shape.fill || "lightblue";
                        shape.fill = "white";
                    }
                    highlightConnectedNodes(obj, "red");
                },
                mouseLeave: function(e, obj, next) {
                    var shape = obj.findMainElement();
                    var original_color = obj.wl.color;

                    if (shape) shape.fill = shape.previousFill;

                    highlightConnectedNodes(obj);
                }

            }
        );

    // each Group is a "swimlane" with a header on the left and a resizable lane on the right
    myDiagram.groupTemplate =
        $(go.Group, HORIZONTAL ? "Horizontal" : "Vertical",
            {
                movable: false, copyable: false, deletable: false,  // can't move or copy or delete lanes
                avoidable: false,
                selectionObjectName: "SHAPE",  // selecting a lane causes the body of the lane to be highlit, not the label
                resizable: true, resizeObjectName: "SHAPE",  // allow lanes to be resized, but the custom resizeAdornmentTemplate only permits one kind of resizing
                layout: $(go.LayeredDigraphLayout,  // automatically lay out the lane's subgraph
                    { direction: HORIZONTAL ? 90 : 0, columnSpacing: 10, layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource }),
                computesBoundsAfterDrag: false,  // needed to prevent recomputing Group.placeholder bounds too soon
                computesBoundsIncludingLinks: false,
                computesBoundsIncludingLocation: true
            },

            // the lane header consisting of a Shape and a TextBlock
            $(go.Panel, "Horizontal",
                {
                    angle: HORIZONTAL ? 270 : 0,  // maybe rotate the header to read sideways going up
                    alignment: go.Spot.Center
                },

                $(go.Shape, "Diamond",
                    { width: 0, height: 0 },
                    new go.Binding("fill", "color")),

                $(go.TextBlock,  // the lane label
                    { font: "bold 14pt Century Gothic" },
                    new go.Binding("text", "key"))
            ),
            // end Horizontal Panel

            $(go.Panel, "Auto",  // the lane consisting of a background Shape and a Placeholder representing the subgraph
                $(go.Shape, "Rectangle",
                    { name: "SHAPE", fill: "white", minSize: computePlaceholderSize(null) },
                    new go.Binding("fill", "color")),
                $(go.Placeholder,
                    { padding: 10, alignment: go.Spot.TopLeft })
            )
            // end Auto Panel
        );
    // end Group

    // define a custom resize adornment that only has a single resize handle
    myDiagram.groupTemplate.resizeAdornmentTemplate =
        $(go.Adornment, "Spot",
            $(go.Placeholder),
            $(go.Shape,  // for changing the length of a lane
                {
                    alignment: HORIZONTAL ? go.Spot.Right: go.Spot.Bottom,
                    desiredSize: HORIZONTAL ? new go.Size(7, 50) : new go.Size(50, 7),
                    fill: "lightblue", stroke: "dodgerblue",
                    cursor: HORIZONTAL ? "col-resize" : "row-resize"
                }),
            $(go.Shape,  // for changing the breadth of a lane
                {
                    alignment: HORIZONTAL ? go.Spot.Bottom : go.Spot.Right,
                    desiredSize: HORIZONTAL ? new go.Size(50, 7) : new go.Size(7, 50),
                    fill: "lightblue", stroke: "dodgerblue",
                    cursor: HORIZONTAL ? "row-resize" : "col-resize"
                })
        );

    myDiagram.linkTemplate =
        $(go.Link,
            { routing: go.Link.AvoidsNodes, corner: 5 },
            { relinkableFrom: true, relinkableTo: true },
            $(go.Shape),
            $(go.Shape, { toArrow: "Standard" }),
            {
                layoutConditions: go.Part.LayoutAdded
            }
        );

    // define some sample graphs in some of the lanes
    myDiagram.model = new go.GraphLinksModel(
        [ // node data
            { key: "First Year"   , isGroup: true, color: "#84ff9e" },
            { key: "Second Year"  , isGroup: true, color: "#dafb69" },
            { key: "Third Year"   , isGroup: true, color: "#fd5c91" },
            { key: "Fourth Year"  , isGroup: true, color: "#6f5cfd" },

            <?php
                if(isset($prospectus['subjects'])){
                    if(!empty($prospectus['subjects'])){
                        foreach($prospectus['subjects'] as $year => $subjects){
                            foreach($subjects as $subject){
                                echo '{key: "' . $subject['course_no'] . '", group: "' . $year . '", color: "' . $subject['color'] . '"},' ;
                            }
                        }
                    }
                }
            ?>
        ],
        [ // link data
            <?php
                if(isset($prospectus['preqs'])){
                    if(!empty($prospectus['preqs'])){
                        foreach($prospectus['preqs'] as $preq){
                            echo "{from: '" . $preq['preq'] . "', to: '" . $preq['subject'] . "'}," ;
                        }
                    }
                }
            ?>
        ]);

    myDiagram.isReadOnly = true;
}
</script>
</head>
<body onload="init()" style="font-family: Century Gothic">
<div id="sample" style="margin-left: 0px">
    <div id="myDiagram" style="border: solid 1px blue; width:100%; height:750px;">
    </div>
</div>
</body>
</html>

回答1:


Here is the node template part containing the mouse enter and leave functions:

     myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        $(go.Shape, "Rectangle",
          { fill: "lightblue", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true },
          new go.Binding("fill", "color")),
        $(go.TextBlock, { margin: 5 },
          new go.Binding("text", "key")),
        // limit dragging of Nodes to stay within the containing Group, defined above
        {
          dragComputation: stayInGroup,
          mouseDrop: function (e, node) {  // dropping a copy of some Nodes and Links onto this Node adds them to this Node's Group
            if (!e.shift && !e.control) return;  // cannot change groups with an unmodified drag-and-drop
            var grp = node.containingGroup;
            if (grp !== null) {
              var ok = grp.addMembers(node.diagram.selection, true);
              if (!ok) grp.diagram.currentTool.doCancel();
            }
          },
          layoutConditions: go.Part.LayoutAdded | go.Part.LayoutNodeSized,

            mouseEnter: function(e, obj, prev) {
                var shape = obj.findMainElement();
                if (shape){
                    shape.previousFill = shape.fill || "lightblue";
                    shape.fill = "white";
                }
                highlightConnectedNodes(obj, "red");
            },
            mouseLeave: function(e, obj, next) {
                var shape = obj.findMainElement();
                var original_color = obj.wl.color;

                if (shape) shape.fill = shape.previousFill;

                highlightConnectedNodes(obj);
            }

        }
      );



Both functions call highlightConnectedNodes function which in turn calls two other functions. One for nodes and one for links.

   function highlightNode(node, color) {
     if (node === null) return;
     var shape = node.findMainElement();
     if (shape === null) return;
     if (color !== undefined) {
       if (!shape.previousStroke) shape.previousStroke = shape.stroke;
       shape.stroke = color;
     } else {  // restore previous color
       shape.stroke = shape.previousStroke;
     }
   }

   function highlightLink(link, color) {
     if (link === null) return;
     var shape = link.findMainElement();
     if (shape === null) return;
     if (color !== undefined) {
       if (!shape.previousStroke) shape.previousStroke = shape.stroke;
       shape.stroke = color;
     } else {  // restore previous color
       shape.stroke = shape.previousStroke;
     }
   }

   function highlightConnectedNodes(node, color) {
     if (node === null) return;

     var lit = node.findLinksInto();

     while (lit.next()) {           
       highlightLink(lit.value, color);
     }

     var nit = node.findNodesInto();

     while (nit.next()) {   
       highlightNode(nit.value, color);
       highlightConnectedNodes(nit.value, color);
     }
   }



When you hover over a node all nodes and links connected to it change color (going backwards). However, if you want only nodes and links forward of the hovered node to change color you can change

findNodesInto
findLinksInto

to

findNodesOutOf 
findLinksOutOf 


Hope that helps.




回答2:


Most likely if you want to highlight nodes as you mouse over them, you really want to use mouseEnter and mouseLeave. Here's a simple example:

  var $ = go.GraphObject.make; // for conciseness in defining templates

  var diagram = $(go.Diagram, "myDiagram", // create a Diagram for the DIV HTML element
    { initialContentAlignment: go.Spot.Center  }); // center the content

  diagram.initialContentAlignment = go.Spot.Center;

  function mouseEnter(e, obj) {
    var shape = obj.findObject('SHAPE');
    shape.fill = "#6DAB80";
    shape.stroke = "#A6E6A1";
    var text = obj.findObject('TEXT');
    text.stroke = "white";
  };

  function mouseLeave(e, obj) {
    var shape = obj.findObject('SHAPE');
    // Return the Shape's fill and stroke to the defaults
    shape.fill = obj.data.color;
    shape.stroke = null;
    // Return the TextBlock's stroke to its default
    var text = obj.findObject('TEXT');
    text.stroke = "black";
  };

  diagram.nodeTemplate =
    $(go.Node, "Auto",
      {
        mouseEnter: mouseEnter,
        mouseLeave: mouseLeave
      },
      $(go.Shape, "Rectangle",
        { strokeWidth: 2, stroke: null, name: 'SHAPE' },
        new go.Binding("fill", "color")),
      $(go.TextBlock,
        { margin: 10, font: "bold 18px Verdana", name: 'TEXT' },
        new go.Binding("text", "key"))
    );

  diagram.model = new go.GraphLinksModel(
  [
    { key: "Alpha", color: "#96D6D9" },
    { key: "Beta",  color: "#96D6D9" },
    { key: "Gamma", color: "#EFEBCA" },
    { key: "Delta", color: "#EFEBCA" }
  ],
  [
    { from: "Alpha", to: "Beta" },
    { from: "Alpha", to: "Gamma" },
    { from: "Beta", to: "Beta" },
    { from: "Gamma", to: "Delta" },
    { from: "Delta", to: "Alpha" }
  ]);

Live example: http://jsfiddle.net/Y5sMN/



来源:https://stackoverflow.com/questions/22677378/apply-onmouseover-on-each-node-gojs-library-swimlane

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!