Create the semi circle around the node with multiple fill colors, on need

Hi,

We have a need to highlight nodes in a custom way, where we need to draw two concentric semicircles around the node and divide the area into segments and color them differently.

Can someone help us with the right way of approach to get to the solution we need? Any help is much appreciated.

Please see the attached wireframe image for more reference. [We are able to draw the nodes in required format, we are looking for help in drawing the semicircles around the node].
Let us know if you need more infomation.

HIghlight_goJS

Thanks
Mithun

Under what conditions would you want to show that for a node? Might you show more than one of them at a time? Would you want to show it whenever a node is selected?

Would it always be a semicircle?

Would the number of sections always be the same? Would the colors always be the same? Or should that information be determined by a data property somehow?

  • [Mithun] : We want to do this while we are highlighting a node.
  • [Mithun] : Yes, we can have multiple nodes highlighted at a time.
  • [Mithun] : Not when node is selected, when there is some external function calling the highlight.
  • [Mithun] : Yes.
  • [Mithun] : Colors and number of sections will be determined by data property and yes the number of such sections could change per node.

image

<!DOCTYPE html>
<html>
<head>
<title>Minimal GoJS Sample</title>
<!-- Copyright 1998-2019 by Northwoods Software Corporation. -->
<meta charset="UTF-8">
<script src="go.js"></script>
<script id="code">
  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
          { "undoManager.isEnabled": true });

    function makeAnnularWedge(angle, sweep, inner) {  // taken from Radial Partition sample
      // the Geometry will be centered about (0,0)
      var outer = inner + 24;  // the outer radius
      var p = new go.Point(outer, 0).rotate(angle);
      var q = new go.Point(inner, 0).rotate(angle + sweep);
      var geo = new go.Geometry()
        .add(new go.PathFigure(-outer, -outer))  // always make sure the Geometry includes the top left corner
        .add(new go.PathFigure(outer, outer))    // and the bottom right corner of the whole circular area
        .add(new go.PathFigure(p.x, p.y)  // start at outer corner, go clockwise
          .add(new go.PathSegment(go.PathSegment.Arc, angle, sweep, 0, 0, outer, outer))
          .add(new go.PathSegment(go.PathSegment.Line, q.x, q.y))  // to opposite inner corner, then anticlockwise
          .add(new go.PathSegment(go.PathSegment.Arc, angle + sweep, -sweep, 0, 0, inner, inner).close()));
      return geo;
    }
    
    var HighlighterTemplate =
      $(go.Adornment, "Spot",
        $(go.Placeholder),  // takes the size and position of the adorned Node
        $(go.Panel,
          new go.Binding("itemArray", "colors"),
          {
            itemTemplate:
              $(go.Panel,  // this Panel.itemIndex will tell us which item it is in the colors Array
                $(go.Shape, { strokeWidth: 0.5, stroke: "gray" },
                  new go.Binding("fill", ""),  // the item will be the CSS color string
                  new go.Binding("geometry", "", function(color, shape) {  // compute the Geometry
                    // ignore the color
                    var colorarr = shape.panel.panel.itemArray;
                    var sweep = 180/colorarr.length;  // cannot be zero, else there wouldn't be any item Panel
                    var i = shape.panel.itemIndex;  // the index of the color in the colors Array
                    var b = shape.part.adornedPart.actualBounds;  // the adorned Node's bounds
                    var radius = Math.sqrt(b.width*b.width/4 + b.height*b.height/4) + 12;
                    return makeAnnularWedge(180 + i * sweep, sweep, radius);
                  })))
          })
      );

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        {
          highlightedChanged: function(node) {
            if (node.isHighlighted && node.data && node.data.colors && node.data.colors.length > 0) {
              var ad = HighlighterTemplate.copyTemplate();
              ad.adornedObject = node;
              node.addAdornment("HIGHLIGHT", ad);
            } else {
              node.removeAdornment("HIGHLIGHT");
            }
          }
          // Alternatively, as a selection Adornment:
          // selectionAdornmentTemplate: HighlighterTemplate
        },
        $(go.Shape,
          { fill: "white", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" },
          new go.Binding("fill", "color")),
        $(go.TextBlock,
          { margin: 8, editable: true },
          new go.Binding("text").makeTwoWay())
      );

    myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Alpha", color: "lightblue", colors: ["red", "orange", "yellow", "green", "blue"] },
      { key: 2, text: "BetaBetaBetaBeta", color: "orange", colors: ["blue"] }
    ]);
  }

  var toggle = true;
  function test() {
    myDiagram.commit(function(diag) {
      if (toggle) diag.nodes.each(function(n) { if (Math.random() < 0.7) n.isHighlighted = true; });
      else diag.clearHighlighteds();
    });
    toggle = !toggle;
  }
</script>
</head>
<body onload="init()">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
  <button onclick="test()">Highlight randomly</button>
</body>
</html>
1 Like

Thanks Walter for your quick reply.
We will use this help and let you know our findings.
Thanks again!

Hi Walter,

Could you also tell us how to add the text inside those segments? Also can we add mouseEnter and mouseLeave functions to those segments to add tooltips for the segments.

Thanks
Mithun

What have you tried so far?

When I added a GraphObject.toolTip to the itemTemplate, it worked as expected.

            {
              toolTip: $("ToolTip", $(go.TextBlock, new go.Binding("text", "")))
            },

We are trying to add text inside each segment.

var HighlighterTemplate =
      $(go.Adornment, "Spot",
        $(go.Placeholder),  // takes the size and position of the adorned Node
        $(go.Panel,
          new go.Binding("itemArray", "colors"),
          {
            itemTemplate:
              $(go.Panel,
                // this Panel.itemIndex will tell us which item it is in the colors Array
                $(go.Shape, { strokeWidth: 0.5, stroke: "gray" },
                  new go.Binding("fill", ""),
  // the item will be the CSS color string
                  new go.Binding("text", "testText"),
                  new go.Binding("geometry", "", function(color, shape) {  // compute the Geometry
                    // ignore the color
                    var colorarr = shape.panel.panel.itemArray;
                    var sweep = 180/colorarr.length;  // cannot be zero, else there wouldn't be any item Panel
                    var i = shape.panel.itemIndex;  // the index of the color in the colors Array
                    var b = shape.part.adornedPart.actualBounds;  // the adorned Node's bounds
                    var radius = Math.sqrt(b.width*b.width/4 + b.height*b.height/4);
                    return makeAnnularWedge(180 + i * sweep, sweep, radius);
                  })))
          })
      );

We could understand that new go.Binding("fill", ""), is filling the background color of each segment. So, we tried to bind text to be shown inside the segment by adding new go.Binding('text','testText'),.

But we are getting this console exception :
‘Binding error: undefined target property: text on Shape(None)#532

We understand that shape doesnt have the text property, so we were wondering how to add the text inside each segment.

And for the tooltip, we wanted to write a html tooltip which will have segment data plus more information of the segment. So, I was trying it with mouseEnter and mouseLeave.

itemTemplate:
              $(go.Panel,
                // this Panel.itemIndex will tell us which item it is in the colors Array
                $(go.Shape, { strokeWidth: 0.5, stroke: "gray" },
                {
                  mouseEnter: function(e,obj){
                      debugger;
                  }
                }...,

Our mouseEnter is getting called but we are failing to know which segment in the shape is calling it. Can you help us in both of these issues?

If you want to show text, you have to use a TextBlock. If you added it to the itemTemplate Panel, you will want to position it somehow. If you leave the Panel as its default Panel.type of “Position”, then you will need to add a Binding of the TextBlock.position property. If you change the panel type to “Spot”, then you will need to bind the TextBlock.alignment property. In either case you will need to have the conversion function compute the correct position or spot.

If you look at the conversion code for the Shape.geometry, you will see that it depends on the Panel.itemIndex to determine which item it represents in the colors Array.

A post was split to a new topic: How to have multiple labels on a link

10 posts were split to a new topic: Clicking and highlighting wedges in a semicircular adornment