apache / echarts

Apache ECharts is a powerful, interactive charting and data visualization library for browser
https://echarts.apache.org
Apache License 2.0
60.4k stars 19.61k forks source link

How to dynamically add images to the rich text of the label on the node? #15948

Open beydeng opened 2 years ago

beydeng commented 2 years ago

What problem does this feature solve?

Lable rich text on nodes can now be dynamically displayed with text, but images cannot be dynamically defined in Rich, so dynamic image addresses cannot be passed as text. All new features that can be added to dynamically transfer image addresses like text?

What does the proposed API look like?

formatter: (userInfo)=>{
        if(data.relate_id){
       return  '{img|userInfo.image}'  '{name_main|'   userInfo.name   '}';
    }else{
       return '{name_main|'   userInfo.name   '}';
     }
    },
rich: {
 name_main: {
       color: 'blue',
        lineHeight: 10,
    verticalAlign: "middle"
},
img: {
    backgroundColor: {
 },
 position: 'center',
 height: 10
 }
}

The address of the image in userInfo.image can then be passed to the image in the IMG style to dynamically display the image.

echarts-bot[bot] commented 2 years ago

Hi! We've received your issue and please be patient to get responded. 🎉 The average response time is expected to be within one day for weekdays.

In the meanwhile, please make sure that it contains a minimum reproducible demo and necessary images to illustrate. Otherwise, our committers will ask you to do so.

A minimum reproducible demo should contain as little data and components as possible but can still illustrate your problem. This is the best way for us to reproduce it and solve the problem faster.

You may also check out the API and chart option to get the answer.

If you don't get helped for a long time (over a week) or have an urgent question to ask, you may also send an email to dev@echarts.apache.org. Please attach the issue link if it's a technical question.

If you are interested in the project, you may also subscribe to our mailing list.

Have a nice day! 🍵

Ovilia commented 2 years ago

Rich text doesn't seem to support image. See if this demo helps.

TSongH2014 commented 1 year ago

Good day Echarts team, I also had problem displaying dynamic images. Below is my code for the 'option/series/label' section:

label: {
   show: true,
   precision: 1,
   fontSize: 30,
   align: 'left',
   position: 'insideRight',
   distance: 100,
   valueAnimation: true,
   fontFamily: 'monospace',
   color: '#aaa',
   formatter: function (value: any) {
      return ' {a|} ' + value.value[0]
   },
   rich: {
      a: {
         height: 35,
            backgroundColor: {                
               // image: "/assets/images/kp.png"
               image: "/assets/images/" + getFlag(imageData) + ".png"
            },
      }
    },
},

As you can see, under the 'rich' section, the 'image' doesn't capture dynamic variable data, how can I solve this?

messiasdias commented 7 months ago
yAxis: {
    //...
    axisLabel: {
      formatter: function (value) {
         //Here I look for rich via numeric key and
         // returning <value> <icon>
        return value + ' {0|}';
      },

      rich: {
         //Here I define the rich via numeric key and it worked
         0 : {
            height: 25,
            align: 'center',
            backgroundColor: {
              image: "<image_path>"
            },
           //...
       }
       }
    },
  },
messiasdias commented 7 months ago

My example code

const flags = {
  'PIX': 'icon_Pix.png',
  'Dinheiro': 'money (1).png',
  'Especie-maos': 'pay.png',
  'Transferência Bancária': 'transference.png',
  'Cartão de Crédito': 'money.png',
  'Cartão de Débito': 'credit-card (1).png'
}

const getFlag = (type) => {
  return `${window.location.origin}/public/img/logos/Img_sgp/${flags[type]}`
}

let options = {
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow'
    }
  },
  xAxis: {
    splitLine: {
      show: false
    }
  },
  yAxis: {
    data: data.series[0].fields[0].values.buffer,
    type: 'category',
    position: 'left',
    inverse: false,
    axisLabel: {
      formatter: function (value) {
        return value + '  {' + Object.keys(flags).indexOf(value) + '|}';
      },
      margin: 20,
      rich: {}
    },
    animationDuration: 300,
    animationDurationUpdate: 300
  },
  series: [
    {
      type: 'bar',
      data: data.series[0].fields[1].values.buffer,
      itemStyle: {
        borderRadius: [0, 7, 7, 0],
        color: 'rgba(5, 192, 145, 0.7)',
      },
      label: {
        show: true,
        position: 'right',
        valueAnimation: true
      }
    }
  ],
  grid: {  // Adiciona configurações para o espaçamento do grid
    left: '4%', // Ajusta a margem esquerda do grid
    right: '10%',
    top: '0%',
    bottom: '0%',
    containLabel: true // Garante que os rótulos estejam contidos no gráfico
  },
}

Object.keys(flags).forEach((type, i) => {
  options.yAxis.axisLabel.rich[i] = {
    height: 25,
    align: 'center',
    backgroundColor: {
      image: getFlag(type)
    }
  }
})

return options
HaidarVladyslav commented 7 months ago

I found one solution The idea is that I have function that returns ChartOptions. As parameter of function I set my ChartData[]. Then I create object rich. I iterate through my array and for every index I insert different rich (with different icons). And then I pass this rich into config. In the formatter we can pass dataIndex that correlates with specific rich[index]. As a result I have this, hope it helps image

interface ChartData {
  value: string;
  name: string;
  color: string;
  icon: string;
};
function transformChartDataToOptions(data: ChartData[]): EChartsOption {
  const rich: any = {};
  data.forEach((d, ind: number) => {
    rich[ind] = {
      backgroundColor: {
        image: d.icon,
      },
      height: 20,
    };
  });
  return {
    series: [
      {
        type: 'pie',
        radius: ['38%', '90%'],
        center: ['60%', '50%'],
        data: data as any,
        color: data.map(value => value.color),
        emphasis: {
          itemStyle: {
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(0, 0, 0, 0.5)',
          }
        },
        label: {
          position: 'inside',
          color: '#fff',
          lineHeight: 21.6,
          fontWeight: 700,
          formatter: function(v) { 
            return [
              `${v.value}`,
              `{${v.dataIndex}|}`
            ].join('\n')
          },
          rich,
        },
      },
    ],
    legend: {
      left: 'left',
      top: 'middle',
      orient: 'vertical',
    }
  }
}

Example Data:

  public ChartData = [
    { value: 16, name: 'Name 1', color: 'red, icon: 'assets/icons/arrow.svg' },
    { value: 28, name: 'Name 2', color: 'green', icon: 'assets/icons/ring.svg' },
  ];
sharma123sunil commented 3 months ago

dynamic image not showing -

const chart_data = [
  {
    type_of: "average",
    icon: 'https://d1a6mr3nq6i4pn.cloudfront.net/co2Reports/assets/images/flag-1.svg',
    value: 2.6769,
    noOfDays: 3,
    vehicleType: "car"
  },
  {
    type_of: "day",
    icon: 'https://d1a6mr3nq6i4pn.cloudfront.net/co2Reports/assets/images/flag-1.svg',
    value: 4.0154,
    noOfDays: 2,
    vehicleType: "bike"
  },
  {
    type_of: "day",
    icon: 'https://d1a6mr3nq6i4pn.cloudfront.net/co2Reports/assets/images/flag-2.svg',
    value: 0,
    noOfDays: 1,
    vehicleType: "train"
  }
];

// Prepare the rich configuration dynamically
const rich_data = {};

// Iterate through chart_data to populate rich_data
chart_data.forEach(item => {
  rich_data[item.vehicleType] = {
    height: 40,
    align: 'center',
    backgroundColor: {
      image: item.icon
    }
  };
});

// Add special handling for the first item (average)
if (chart_data.length > 0) {
  const firstItem = chart_data[0];
  rich_data.Average = {
    height: 20,
    align: 'center',
    backgroundColor: {
      image: '' // Replace with your average icon URL
    }
  };
}

// Define the ECharts option object
 option = {
  color: ["#3398DB"],
  tooltip: {
    trigger: "axis",
    axisPointer: {
      type: "shadow"
    }
  },
  grid: {},
  xAxis: [{
    type: "category",
    data: chart_data.map((item, index) => index === 0 ? 'Average' : item.icon), // Set xAxis data based on vehicleType
    axisLabel: {
      formatter: function (value) {
        console.log(value)
        if (value === 'Average') {
          return [
            `{${value}|}`,
            `${value}`
          ].join('\n');
        } else {
          return value // Leave label text empty to only show icon
        }
      },
      rich: rich_data
    }
  },
                    ],
  yAxis: [{
    type: "value"
  }],
  series: [{
    name: "test",
    type: "bar",
    barWidth: "60%",
    data: chart_data.map(item => item.value) // Set series data with values
  }]
};
// Add second xAxis configuration
// Add second xAxis configuration
option.xAxis.push({
  type: 'category',
  position: 'bottom',
  data: chart_data.map((item, index) => index === 0 ? '' : `${item.noOfDays}x`),
  axisLine: {
    show: true,
    lineStyle: {
      color: '#000', // Change this to your desired color
      width: 2, // Adjust the width if necessary
    },
  },
  axisLabel: {
    margin: 50,
    color: '#000',
    formatter: function (value, index) {
      if (index === 0) {
        return '';
      } else {
        return `{${index}|${value}}`;
      }
    },
    rich: chart_data.reduce((acc, item, index) => {
      if (index !== 0) {
        acc[index] = {
          padding: [10, 15, 10, 15],
          backgroundColor: 'rgba(34, 34, 34, 0.3)',
          borderRadius: [50, 50, 50, 50]
        };
      }
      return acc;
    }, {})
  }
});