2

我已经完成了第一部分,在每个节点上添加了颜色。下一步是如何在每个节点上添加 onmouseover 然后在属于悬停节点的子图(包括连接它的链接/线)上突出显示/应用样式。

有谁知道?

到目前为止,这是我的代码:

        <?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>
4

2 回答 2

3

这是包含鼠标进入和离开功能的节点模板部分:

     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);
            }

        }
      );



这两个函数都调用 highlightConnectedNodes 函数,该函数又调用另外两个函数。一个用于节点,一个用于链接。

   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);
     }
   }



当您将鼠标悬停在一个节点上时,所有连接到它的节点和链接都会改变颜色(向后)。但是,如果您只希望悬停节点前面的节点和链接更改颜色,则可以更改

findNodesInto
findLinksInto

findNodesOutOf 
findLinksOutOf 


希望有帮助。

于 2014-03-27T12:59:31.793 回答
3

最有可能的是,如果您想在鼠标悬停时突出显示节点,您真的想使用mouseEnterand mouseLeave。这是一个简单的例子:

  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" }
  ]);

现场示例:http: //jsfiddle.net/Y5sMN/

于 2014-03-27T14:14:01.027 回答