Graduated panels reversed graduation

Hey,

I have two graduated panels:

Slider (Linear)
Gauge (Circular)

And I want to switch the display of the graduation tick texts.

To

For the Slider, the maximum will be in the bottom side. For the Gauge, the maximum will be displayed on the left side.

The first case is covered by one of the examples on this page Graduated Panels | GoJS

Note how the Geometry goes from 0,0 to 0,-400, because negative Y values are higher on the screen/page. Note how because everything is relative to the path, the tick marks and labels would be on the opposite side, so we have also changed the alignmentFocus and segmentOffset to have opposite values from the previous example.

However, I struggle to do the same for the Knob.

First, because I am unable to display the geometry string on the SVG tool that I use SvgPathEditor
My GeometryString is M -70.71 70.71 B135 270 0 0 100 100 M0 100
I understand that’s because the B option that I am using, which is specific to gojs. (See here Geometry Path Strings | GoJS)

Still, is there any way to visualize this on an online tool or something? It is quite challenging to work with these shapes blindly.

Second, and to be honest, I am not quite sure how I should reverse this circular shape. I understand for a linear shape it should go from 0 to a negative value in order to get a reversed graduation. But I am afraid it is not that simple for a circular shape. I really suggest adding something about that in the documentation and maybe give me a hint to better understand how I should solve this issue.

Thank you.

Look at the differences to see how to do this:

<!DOCTYPE html>
<html>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:400px"></div>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>

  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
const $ = go.GraphObject.make;
const myDiagram =
  new go.Diagram("myDiagramDiv", {
      "undoManager.isEnabled": true,
      "ModelChanged": e => {     // just for demonstration purposes,
        if (e.isTransactionFinished) {  // show the model data in the page's TextArea
          document.getElementById("mySavedModel").textContent = e.model.toJson();
        }
      }
    });

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    { locationSpot: go.Spot.Center },
    $(go.Shape, "Circle",
      { stroke: "orange", strokeWidth: 5, spot1: go.Spot.TopLeft, spot2: go.Spot.BottomRight },
      new go.Binding("stroke", "color")),
    $(go.Panel, "Spot",
      $(go.Panel, "Graduated",
        {
          name: "SCALE", margin: 14, graduatedTickUnit: 2.5, graduatedMax: 120,
          stretch: go.Stretch.None  // needed to avoid unnecessary re-measuring!!!
        },
        // "M-70.7107 70.7107 B135 270 0 0 100 100 M0 100"
        // "M70.7107 70.7107 B45 -270 0 0 100 100 M0 100"
        $(go.Shape, { name: "SHAPE", geometryString: "M70.7107 70.7107 B45 -270 0 0 100 100 M0 100", stroke: "white", strokeWidth: 4 }),
        $(go.Shape, { geometryString: "M0 0 v-10", alignmentFocus: go.Spot.Bottom, stroke: "white", strokeWidth: 1.5 }),
        $(go.Shape, { geometryString: "M0 0 v-12", alignmentFocus: go.Spot.Bottom, stroke: "white", strokeWidth: 2.5, interval: 2 }),
        $(go.Shape, { geometryString: "M0 0 v-15", alignmentFocus: go.Spot.Bottom, stroke: "white", strokeWidth: 3.5, interval: 4 }),
        $(go.TextBlock,
          {
            interval: 4,
            alignmentFocus: go.Spot.Center,
            font: "bold italic 14pt sans-serif", stroke: "white",
            segmentOffset: new go.Point(0, -30)
          })
      ),
      $(go.TextBlock,
        { alignment: new go.Spot(0.5, 0.9), stroke: "orange", font: "bold italic 14pt sans-serif" },
        new go.Binding("text", "key"),
        new go.Binding("stroke", "color")),
      $(go.Shape, { fill: "red", strokeWidth: 0, geometryString: "F1 M-6 0 L0 -6 100 0 0 6z x M-100 0" },
        new go.Binding("angle", "value", convertValueToAngle)),
      $(go.Shape, "Circle", { width: 2, height: 2, fill: "#444" })
    )
  );

function convertValueToAngle(v, shape) {
  const scale = shape.part.findObject("SCALE");
  const p = scale.graduatedPointForValue(v);
  shape = shape.part.findObject("SHAPE");
  const c = shape.actualBounds.center;
  return c.directionPoint(p);
}

myDiagram.model = new go.GraphLinksModel(
  [
    { key: "Alpha", value: 23 },
    { key: "Beta", color: "green", value: 70 }
  ], [
  { from: "Alpha", to: "Beta" }
]);

function loop() {
  setTimeout(() => {
    myDiagram.startTransaction();
    myDiagram.nodes.each(node => {
      const scale = node.findObject("SCALE");
      if (scale === null || scale.type !== go.Panel.Graduated) return;
      const min = scale.graduatedMin;
      const max = scale.graduatedMax;
      let v = node.data.value || Math.floor((max - min) / 2);
      if (v < min) v++;
      else if (v > max) v--;
      else v += (Math.random() < 0.5) ? -1 : 1;
      myDiagram.model.setDataProperty(node.data, "value", v);
    });
    myDiagram.commitTransaction("modified Graduated Panel");
    loop();
  }, 100);
}

loop();
  </script>
</body>
</html>