cancel
Showing results for 
Search instead for 
Did you mean: 

How to show 2 colors for 1 legend item?

DXC
8 - Cloud Apps
8 - Cloud Apps

I am building a bar chart show actual vs target number. And in my actual number, I am using a conditional color if it is over the target then show yellow if not show blue here. 
After I added the conditional color on the "Actual sale" value, the legend item colors are all in grey. Is there a way to show this icon color as how it is on the values on left panel (blue + yellow color)? 

DXC_1-1736988684777.png

color wanted: 

DXC_0-1736988662577.png

 

 

 

 

1 ACCEPTED SOLUTION

TriAnthony
Community Team Member
Community Team Member

Hi @DXC,

Below is a script you can use to replace the grey box for the measure with conditional formatting with a two-tone box, one for each of the selected colors. If you need to reuse the script for another widget, make sure to update the line below with the correct measure name.

const measureName = "Actual Sale"

Example:

TriAnthony_1-1737140535789.png

Script:

 

widget.on("ready", function(se, ev) {

  // Define the measure name
  const measureName = "Actual Sale";

  // Define a unique ID for the two-tone legend item
  const legendItemID = "two-tone-" + widget.oid + "-" + measureName.replace(/\s+/g, "") + "-legend-item";

  // Find the metadata of the measure
  const measureMetadata = widget.metadata.panels[1].items.find((item) => {
    if (item.jaql && item.jaql.title.indexOf(measureName) !== -1) {
      return true;
    }
  });

  // Define the gradient colors as variables
  const color1 = measureMetadata.format.color.conditions[0].color;
  const color2 = measureMetadata.format.color.conditions[1].color;

  // Find the text element for the measure
  const legendItemText = Array.from(element.get(0).querySelectorAll("text")).find(
    (textElement) => textElement.textContent.trim() === measureName
  );

  if (legendItemText) {
    // Locate the parent <g> group containing the text and rect
    const parentGroup = legendItemText.closest("g");

    if (parentGroup) {
      // Find the associated <rect> element
      const rectElement = parentGroup.querySelector("rect.highcharts-point");

      if (rectElement) {
        // Create a <defs> element for the gradient
        const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
        const gradient = document.createElementNS("http://www.w3.org/2000/svg", "linearGradient");
        gradient.setAttribute("id", legendItemID);
        gradient.setAttribute("x1", "0%");
        gradient.setAttribute("y1", "0%");
        gradient.setAttribute("x2", "100%");
        gradient.setAttribute("y2", "0%");

        // Create gradient stops
        const stop1 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
        stop1.setAttribute("offset", "50%");
        stop1.setAttribute("style", `stop-color: ${color1}; stop-opacity: 1`);

        const stop2 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
        stop2.setAttribute("offset", "50%");
        stop2.setAttribute("style", `stop-color: ${color2}; stop-opacity: 1`);

        // Append stops to the gradient
        gradient.appendChild(stop1);
        gradient.appendChild(stop2);
        defs.appendChild(gradient);

        // Insert the <defs> into the SVG root (if not already present)
        let svgRoot = rectElement.closest("svg");
        if (!svgRoot) {
          // Wrap the rect in a new SVG if one isn't present
          svgRoot = document.createElementNS("http://www.w3.org/2000/svg", "svg");
          svgRoot.setAttribute("width", "20");
          svgRoot.setAttribute("height", "20");
          rectElement.parentNode.replaceChild(svgRoot, rectElement);
          svgRoot.appendChild(rectElement);
        }
        svgRoot.insertBefore(defs, svgRoot.firstChild);

        // Apply the gradient to the rect
        rectElement.setAttribute("fill", `url(#${legendItemID})`);
      }
    }
  }

});

 

Tri Anthony Situmorang

View solution in original post

4 REPLIES 4

TriAnthony
Community Team Member
Community Team Member

Hi @DXC,

Below is a script you can use to replace the grey box for the measure with conditional formatting with a two-tone box, one for each of the selected colors. If you need to reuse the script for another widget, make sure to update the line below with the correct measure name.

const measureName = "Actual Sale"

Example:

TriAnthony_1-1737140535789.png

Script:

 

widget.on("ready", function(se, ev) {

  // Define the measure name
  const measureName = "Actual Sale";

  // Define a unique ID for the two-tone legend item
  const legendItemID = "two-tone-" + widget.oid + "-" + measureName.replace(/\s+/g, "") + "-legend-item";

  // Find the metadata of the measure
  const measureMetadata = widget.metadata.panels[1].items.find((item) => {
    if (item.jaql && item.jaql.title.indexOf(measureName) !== -1) {
      return true;
    }
  });

  // Define the gradient colors as variables
  const color1 = measureMetadata.format.color.conditions[0].color;
  const color2 = measureMetadata.format.color.conditions[1].color;

  // Find the text element for the measure
  const legendItemText = Array.from(element.get(0).querySelectorAll("text")).find(
    (textElement) => textElement.textContent.trim() === measureName
  );

  if (legendItemText) {
    // Locate the parent <g> group containing the text and rect
    const parentGroup = legendItemText.closest("g");

    if (parentGroup) {
      // Find the associated <rect> element
      const rectElement = parentGroup.querySelector("rect.highcharts-point");

      if (rectElement) {
        // Create a <defs> element for the gradient
        const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
        const gradient = document.createElementNS("http://www.w3.org/2000/svg", "linearGradient");
        gradient.setAttribute("id", legendItemID);
        gradient.setAttribute("x1", "0%");
        gradient.setAttribute("y1", "0%");
        gradient.setAttribute("x2", "100%");
        gradient.setAttribute("y2", "0%");

        // Create gradient stops
        const stop1 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
        stop1.setAttribute("offset", "50%");
        stop1.setAttribute("style", `stop-color: ${color1}; stop-opacity: 1`);

        const stop2 = document.createElementNS("http://www.w3.org/2000/svg", "stop");
        stop2.setAttribute("offset", "50%");
        stop2.setAttribute("style", `stop-color: ${color2}; stop-opacity: 1`);

        // Append stops to the gradient
        gradient.appendChild(stop1);
        gradient.appendChild(stop2);
        defs.appendChild(gradient);

        // Insert the <defs> into the SVG root (if not already present)
        let svgRoot = rectElement.closest("svg");
        if (!svgRoot) {
          // Wrap the rect in a new SVG if one isn't present
          svgRoot = document.createElementNS("http://www.w3.org/2000/svg", "svg");
          svgRoot.setAttribute("width", "20");
          svgRoot.setAttribute("height", "20");
          rectElement.parentNode.replaceChild(svgRoot, rectElement);
          svgRoot.appendChild(rectElement);
        }
        svgRoot.insertBefore(defs, svgRoot.firstChild);

        // Apply the gradient to the rect
        rectElement.setAttribute("fill", `url(#${legendItemID})`);
      }
    }
  }

});

 

Tri Anthony Situmorang

Hi @TriAnthony  this works PERFECT!! Appreciate your help!! 

Hi @TriAnthony  thank you again on sharing this script! On my dashboard, there are a few more different widgets but with the same Target Sales and Actual Sales measure names. After I apply this script in all widgets, only one widget has the updated 2 tone color, the rest are still in grey. Is there a way to make them all work? 

TriAnthony
Community Team Member
Community Team Member

Hi @DXC,

Thank you for pointing that out! I have updated the script in my original comment. It now works for all widgets the script is applied to, and the legend colors are consistent with the colors selected at the widget configuration.

See an example below.

TriAnthony_0-1738260323047.png

Tri Anthony Situmorang