Search code examples
c++openinventor

How do you set annotation color for PoPieChartRep?


In short, how i set custom colors(different than slice) for labels of PoPieChartRep?

In more detail: I'm trying to create a Pie chart with OIV's PoPieChartRep class, and i would like that the strings "Value1" and "Value2" have specific colors.

Simple pie chart

I saw a field in the online reference of PoPieChartRep, and setting isAnnoSliceColor to false makes the labels white.

I suspect i should use material to set the color, but don't know which object should have it? Also checked PoLabelHints and PoMiscTextAttr as the reference suggests it, but not found any color/material related field.


Solution

  • Just for reference, setting all the labels to the same color is easy. PoPieChartRep contains an SoAppearanceKit named "annotationApp", so you just need:

    auto appKit = (SoAppearanceKit*)pieChart->getPart("annotationApp", TRUE);
    auto appMat = (SoMaterial*)appKit->getPart("material", TRUE);
    appMat->diffuseColor.setValue(1, 0.5f, 0);
    

    Setting a different color for each label is not "built-in", but it's possible by modifying the pie chart's internal scene graph. Our goal is to insert an SoMaterial node before each text label node. We know that PoPieChartRep contains an SoGroup name "annotation" and its children are the text labels (we don't care about their internal structure). Start by setting the 'isAnnoSliceColor' field to false, so the pie chart will not create material nodes for the labels. One gotcha: You need to know that PoPieChartRep will not actually create the text label nodes until the first traversal. You could apply an action to force this or simply do the modification after calling setScenegraph() on the viewer. The modification could be something like this:

      SbColor textColors[] = { {1,0,0}, {0,1,0}, {0,0,1}, {1,1,0}, {1,0,1}, {0,1,1},
        {1,0.5f,0}, {1,0,0.5f}, {0.5f,1,0}, {0.5f,0,1} };
      auto appGroup = (SoGroup*)pieChart->getPart("annotation", TRUE);
      int numText = appGroup->getNumChildren();
      int insertIndex = 0;
      for (int i = 0; i < numText; ++i) {
        auto matNode = new SoMaterial();
        matNode->diffuseColor.setValue(textColors[i]);
        appGroup->insertChild(matNode, insertIndex);
        insertIndex += 2;
      }
    

    The correct practice is to put this code in a function and set that function to be called automatically when the pie chart internal nodes are created, using addPostRebuildCallback().

    enter image description here