【问题标题】:Apply onmouseover on each node - GOjs library - swimlane在每个节点上应用 onmouseover - GOjs 库 - 泳道
【发布时间】:2014-05-05 19:43:56
【问题描述】:

我已经完成了first part,在每个节点上添加了颜色。下一步是如何在每个节点上添加 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>

【问题讨论】:

    标签: javascript html css json gojs


    【解决方案1】:

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

         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 
    


    希望对您有所帮助。

    【讨论】:

    • 非常感谢@James 先生!我希望你很快还在外面,因为对于我们的最终项目,我仍然有很多与这个库有关的问题。
    • 我只需要在这里发布这个作为后续问题。
      先生,你能用你的代码绑定this吗?我已经实现了上面的代码并且运行良好(我喜欢它,谢谢!我只需要加厚链接,更改颜色等)。我真正想要添加的功能是当a节点悬停时,它还会显示其详细信息。
    • P.S.先生是否可以保留悬停节点的颜色?因为每当我将鼠标悬停在非白色节点上时,它就会在悬停时变为白色。
    【解决方案2】:

    如果您想在将鼠标悬停在节点上时突出显示节点,则很可能您真的想使用mouseEntermouseLeave。这是一个简单的例子:

      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/

    【讨论】:

    • 谢谢先生,我知道这段代码会派上用场,我只需要用我的你来实现它。嗯……先生,可以像this这样吗?它表示显示的详细信息是有关悬停节点的信息。我还没有传递信息(来自控制器,因为我正在使用 CI 框架),所以如果你创建一个你的虚拟对象就可以了。
    • 谢谢先生,但如果您能帮我用我的程序实现它,我将不胜感激 =)。先生?
    • 先生,我在处理数据可视化代码时遇到了问题。因为据我所知,模型是通过细节本身创建的。我想要的是,除了我拥有的模型之外,我还想为细节创建另一个实体。 T_T 也许你有什么想法?
    猜你喜欢
    • 2014-05-05
    • 2015-04-16
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多