본문 바로가기

프로그래밍/웹

Chart.js 버그 픽스 컨트리뷰션

회사에서 신규 화면 구성을 위해 Chart.js를 사용하던 중 복장터지는 레이아웃 버그를 하나 만나게 되는데... 

 

바로 이 툴팁의 위치가 미묘하게 왼쪽으로 틀어져버리는 버그였다. Chart.js 옵션 중 stack이라는 것을 활용하면 위처럼 하나의 bar 엘레먼트에 두 데이터를 쌓아서 표시할 수 있는데, 이 경우에 툴팁의 포지션이 틀어져버리는 것이었다.

 

왜그러는 것인가.. 소스 코드를 분석하던 중 툴팁 관련 로직이 모여있는 plugin.tooltip.js 파일을 발견. 이 파일 안에 있는 `positioners.average` 함수가 툴팁의 위치를 계산해주는 놈이었다.

const positioners = {
  average(items) {
    if (!items.length) {
      return false;
    }

    let i, len;
    let x = 0;
    let y = 0;
    let count = 0;

    for (i = 0, len = items.length; i < len; ++i) {
      const el = items[i].element;
      if (el && el.hasValue()) {
        const pos = el.tooltipPosition();
        x += pos.x;
        y += pos.y;
        ++count;
      }
    }

    return {
      x: x / count,
      y: y / count
    };
  },
// ...
}

 

모든 아이템의 x 값을 다 더해서 평균을 내기 때문에 stack 기능을 사용하는 경우 stack이 생긴 요소의 x 값이 중복으로 더해지기 때문에  포지션이 쏠리는 현상이 발생하게 된다. 즉 중복된 x 포지션 값이 온다면 평균 계산에 포함시키지 않고 무시해줘야 하는 상황.

 

깔끔하게 Set으로 개선.

const positioners = {
  average(items) {
    if (!items.length) {
      return false;
    }

    let i, len;
    // x 값들을 다 더하지 않고 Set으로 변경
    let xSet = new Set();
    let y = 0;
    let count = 0;

    for (i = 0, len = items.length; i < len; ++i) {
      const el = items[i].element;
      if (el && el.hasValue()) {
        const pos = el.tooltipPosition();
        // 여기서 중복된 x 값이 들어오게 된다면 무시된다
        xSet.add(pos.x);
        y += pos.y;
        ++count;
      }
    }

    const xAverage = [...xSet].reduce((a, b) => a + b) / xSet.size;

    return {
      x: xAverage,
      y: y / count
    };
  },
// ...
}

 

코드 수정후 해당 변경에 대한 테스트 코드까지 작성해서 Pull Request 생성.

 

메인테이너 두 명의 승인 후 머지까지 일사천리로 진행되어 기분이 좋다. :)