차트라이브러리/FusionCharts

Chart.js에서 custom-tooltip에 image 올리기

세리둥절 2022. 2. 25. 11:59
반응형

 

 

 

✔️ 필요성

무료이고 가벼워서 차트 라이브러리로 많이 쓰이는 chart.js! 리액트 계열에서 사용할 때에는 react wrapper인 react-chartjs-2 를 사용하면 된다.

 

chart.js의 custom-tooltip을 만들 때 이미지를 툴팁에 포함하고 싶을 때는 조금 어렵지만 아래와 같이 하면 된다. 공식 문서와 stack-overflow를 이틀간 삽질해서 겨우 성공했다.

 

https://www.chartjs.org/docs/latest/configuration/tooltip.html#external-custom-tooltips

 

Tooltip | Chart.js

Namespace: options.plugins.tooltip, the global options for the chart tooltips is defined in Chart.defaults.plugins.tooltip. WARNING The bubble, doughnut, pie, polar area, and scatter charts override the tooltip defaults. To change the overrides for those c

www.chartjs.org

https://stackoverflow.com/questions/59986669/chartjs-custom-tooltip-with-icon

 

ChartJS - Custom tooltip with icon

Is there an option to create custom tooltips with ChartJS in Angular which displays custom icon on the left side and some data parameters on the right side (50% 50% witdh). I've seen some ideas but...

stackoverflow.com

 

✔️ 문제 해결 

일단 텍스트와 이미지를 함께 툴팁에 올리고, 이미지는 height와 width를 함께 활용해서 사이즈를 조정할 수 있다.

 

여기에 그치지 않고 앞으로 그 외 background 등을 더더욱 꾸며나가야할 일이 산더미인 것은 사실.

tooltip: {
        // Disable the on-canvas tooltip
        enabled: false,

        external: function (context: any) {
          // Tooltip Element
          let tooltipEl = document.getElementById("chartjs-tooltip");

          // Create element on first render
          if (!tooltipEl) {
            tooltipEl = document.createElement("div");
            tooltipEl.id = "chartjs-tooltip";
            tooltipEl.innerHTML = "<table></table>";
            document.body.appendChild(tooltipEl);
          }

          // Hide if no tooltip
          const tooltipModel = context.tooltip;
          if (tooltipModel.opacity === 0) {
            tooltipEl.style.opacity = "0";
            return;
          }

          // Set caret Position
          tooltipEl.classList.remove("above", "below", "no-transform");
          if (tooltipModel.yAlign) {
            tooltipEl.classList.add(tooltipModel.yAlign);
          } else {
            tooltipEl.classList.add("no-transform");
          }

          function getBody(bodyItem: any) {
            return bodyItem.lines;
          }

          // Set Text
          if (tooltipModel.body) {
            const titleLines = tooltipModel.title || [];
            const bodyLines = tooltipModel.body.map(getBody);

            const tableHead = document.createElement("thead");

            titleLines.forEach((title: any) => {
              const tr = document.createElement("tr");
              tr.style.borderWidth = "0";

              const th = document.createElement("th");
              th.style.borderWidth = "0";
              const text = document.createTextNode(title);
              th.appendChild(text);

              // THIS BLOCK ADDED
              const imageTh = document.createElement("th");
              th.style.borderWidth = "0";
              const image = document.createElement("img");
              image.src = "https://i.ibb.co/qRk3DfC/congestion-step3.png"; //context.tooltip.dataPoints[0].dataset.url;
              image.height = 40;
              image.width = 40;
              imageTh.appendChild(image);

              tr.appendChild(th);
              tr.appendChild(imageTh);
              tableHead.appendChild(tr);
            });
            const tableRoot = tooltipEl.querySelector("table");

            // Remove old children
            if (tableRoot && tableRoot.firstChild) {
              while (tableRoot.firstChild) {
                tableRoot.firstChild.remove();
              }
            }
            // Add new children
            tableRoot?.appendChild(tableHead);
          }

          const position = context.chart.canvas.getBoundingClientRect();
          // const bodyFont = Chart.helpers.toFont(tooltipModel.options.bodyFont);

          // Display, position, and set styles for font
          tooltipEl.style.opacity = "1";
          tooltipEl.style.position = "absolute";
          tooltipEl.style.left =
            position.left + window.pageXOffset + tooltipModel.caretX + "px";
          tooltipEl.style.top =
            position.top + window.pageYOffset + tooltipModel.caretY + "px";
          // tooltipEl.style.font = bodyFont.string;
          tooltipEl.style.padding =
            tooltipModel.padding + "px " + tooltipModel.padding + "px";
          tooltipEl.style.pointerEvents = "none";
        },
      },

 

 

반응형