[프로젝트] Highcharts treemap dataLabels 관련 기능 구현

ljk4268·2023년 11월 26일
0

현재 진행 중인 프로젝트에는 사용자가 쉽게 데이터를 파악하고 시각화하기 위한 차트페이지가 있다.
차트페이지에는 Highcharts의 treemap으로 데이터를 그리는 부분이 있는데

이녀석이 아주 골칫덩어리였다 😑😑😑


✅ 골칫덩어리가 된 이유


( Highcharts treemap 데모 페이지: https://www.highcharts.com/demo/highcharts/treemap-coloraxis)

위 이미지처럼 Highcharts의 treemap는 기본적으로 data의 name을 차트상 보여준다.
name이 노출되는 부분을 내가 원하는 형태의 text로 변경하고 싶으면
series.dataLabels.pointFormat 속성을 커스텀 하면 된다.

내가 진행하고 있는 프로젝트는 series.dataLabels.pointFormat속성에 꽤 많은 text를 넣고 있다.
treemap의 크기가 작은 경우,
편하게 말하면 treemap으로 그려지는 네모칸이 작은 경우
text를 라이브러리자체에서 text-overflow:ellipsis;시키거나 아예 화면에서 보이지 않게 hidden처리를 해버린다.

💡 hidden처리를 해버린다. << 여기서 나의 문제가 시작되었다.

Highcharts 라이브러리에서 dataLables를 hidden 시키는데에 어떠한 규칙이 있었으면 좋겠는데
눈으로 봤을 때 비슷해보이는 네모칸인데
어떤 네모칸안의 text는 노출이 되고
어떤 네모칸 안의 text는 노출이 안된다
...

윽 . . .😑😑😑

클라이언트도 크기가 같아 보이는 네모칸에 어떤 데이터는 노출이 되고 어떤 데이터는 노출이 되지 않으니 이상하다 느끼고 문제제기를 했다.


✅ 문제를 해결해야 한다.(stackoverflow 사랑해요)

급한건은 아니였지만, 문제제기가 된 이상 최대한 빠른 시일내에 해결하고 싶었다.
시간이 남는대로 내가 겪는 문제와 비슷한 내용의 글들이 있는지 구글링을 했고,
여러 단어를 바꿔가며 구글링한 결과 하나의 글을 발견할 수 있었다.

https://stackoverflow.com/questions/53723536/highcharts-treemap-data-labels-overflow

해당 글을 보면 해결 방법으로 각 데이터 포인트를 반복하여 treemap의 네모칸과 그 안에 그려지는 라벨의 크기를 비교할 수 있으니,
두 크기를 비교해서 라벨의 크기가 더 큰 경우 css로 숨기라는 것이였다.

chart: {
  type: 'treemap',
  width: 500,
  events: {
    load: function() {
      var chart = this,
        series = chart.series[0],
        pointWidth,
        labelWidth;

      series.data.forEach(function(point) {
        if (point.dataLabel) {
          pointWidth = point.shapeArgs.width;
          labelWidth = point.dataLabel.width;

          if (labelWidth > pointWidth) {
            point.dataLabel.hide();
          }
        }
      });
    }
  }
}

✅ 해결방법은 찾았다! 그러나 해결은...🥲

stackoverflow에서 알려준 코드로 해결방향은 찾아냈지만 해결은 할 수 없었다.
위에서는 treemap의 네모크기와 dataLable의 크기를 비교하라고 되어있다.

나의 경우 데이터라벨에 들어가는 내용을 title과 description으로 나누어 html로 넣고 있었고
treemap의 네모크기보다 text가 긴 경우 white-space: normal로 줄바꿈처리를 해주고 있다.

근데 labelWidth = point.dataLabel.width; << 해당 코드가 알려주는 너비는 줄바꿈처리 하기 전의 너비를 알려주고 있다.

나는 줄바꿈처리가 된 후의 dataLable의 크기가 필요하니 원하는 크기를 찾기 위한 방법을 찾아야했다.


✅ 나의 해결 방법

  1. series.dataLabels.pointFormat에 들어가는 title과 description 태그에 class를 부여해준다.
  2. dataLabel에 들어가있는 원하는 요소를 가져와서 변수로 만들어둔다.
series.data.forEach((point) => {
  if (point.dataLabel) {
  	const label = point.dataLabel.div;
    const title = label.querySelector('.지정한 class이름');
    const description = label.querySelector('.지정한 class이름');
  }
  1. 가져온 정보에서 width, height 값을 구한다. (요소 전체 크기와 높이를 가져온다.)
const titleWidth = title.offsetWidth;
const titleHeight = title.offsetHeight;
const descriptionWidth = description.offsetWidth;
const descriptionHeight = description.offsetHeight;

offsetWidth, offsetHeight사용했는데 이 부분에 대해 궁금하면 아래 블로그를 참고하시면 됩니다.
(엘리먼트의 크기 가져오기: https://ohgyun.com/571)

  1. 네모박스 크기와 요소 크기 비교해서 opacity처리 해준다. (아래 코드는 예시)
if (titleWidth > pointWidth) {
  label.style.opacity = 0;
} else {
  label.style.opacity = 1;
}

나의 경우는
treemap 네모박스 너비와 높이가 50미만 이거나 타이틀높이가 네오박스 높이보다 큰 경우는 dataLabel을 노출 하지 않는다 등
클라이언트와 상의하에 클라이언트가 만족할만한 조건을 여러가지 넣어두었다.


✔️ 숙원사업 해결

이 문제해결은 나에게 숙원사업과도 같은 느낌이다!
treemap에 대해 클라이언트가 요구하는게 많았었는데 급한건 먼저 처리하다보니 해결 순서가 뒤로 밀리기도 했고,
딱히 방법이 없을거 같다는 선임의 말에 포기해야하나 했던 부분이기도 하다!

시간적인 여유가 있을 때마다 진짜 엄청 구글링 했고 ㅠㅠㅠㅠ
내가 원하던 방향의 글을 찾게 되어서 해결해내고야 말았다! 💪🏻

헿 뿌듯해 뿌듯해 뿌우우우우듯해!!! 😁😁😁

profile
적응중

0개의 댓글