From eb4c5e9cbdb11942ce9f3eb41fad6424272aa738 Mon Sep 17 00:00:00 2001 From: Jin-Hee Park <53548023+jhee564@users.noreply.github.com> Date: Fri, 26 Mar 2021 13:52:02 +0900 Subject: [PATCH] =?UTF-8?q?[#791][3.0]=20Bar=20Chart=20-=20borderRadius=20?= =?UTF-8?q?=EC=98=B5=EC=85=98=20=EC=B6=94=EA=B0=80=20(#795)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [#791][3.0] Bar Chart - borderRadius 옵션 추가 - 'borderRadius' 옵션 추가 및 기본값 0으로 설정 - radius 공통 처리를 위하여 일반적으로 막대를 그리는 부분과, 마우스 오버시 하이라이트 처리와 함께 막대를 그리는 부분의 로직을 통합 - borderRadius 관련 설명 작성 * [#791][3.0] Bar Chart - borderRadius 옵션 추가 - value Label이 그려지지 않는 현상 해결 * [#791][3.0] Bar Chart - borderRadius 옵션 추가 - 코드 충돌나는 부분 merge 후 commit Co-authored-by: jinhee park --- docs/views/barChart/api/barChart.md | 1 + docs/views/barChart/example/Gradient.vue | 1 + docs/views/barChart/example/Horizontal.vue | 3 +- src/components/chart/chart.core.js | 4 +- src/components/chart/element/element.bar.js | 79 +++++++++++++++++++-- src/components/chart/uses.js | 1 + 6 files changed, 82 insertions(+), 7 deletions(-) diff --git a/docs/views/barChart/api/barChart.md b/docs/views/barChart/api/barChart.md index c88860ff5..7ac2115b6 100644 --- a/docs/views/barChart/api/barChart.md +++ b/docs/views/barChart/api/barChart.md @@ -71,6 +71,7 @@ const chartData = { | width | String / Number | '100%' | 차트의 너비 | '100%', '150px', 150 | | height | String / Number | '100%' | 차트의 높이 | '100%', '150px', 150 | | thickness | Number | 1 | 차트 막대의 너비 | 0.1 ~ 1 | + | borderRadius | Number | 0 | 막대 가장자리 부분의 border-radius 값. | 0 ~ | | horizontal | Boolean | false | 차트 막대의 방향 - 수평 전환 여부 | true, false | | axesX | Object | 없음 | X축에 대한 속성 | [상세](#axesx-axesy) | | axesY | Object | 없음 | Y축에 대한 속성 | [상세](#axesx-axesy) | diff --git a/docs/views/barChart/example/Gradient.vue b/docs/views/barChart/example/Gradient.vue index 162d09184..431ae515a 100644 --- a/docs/views/barChart/example/Gradient.vue +++ b/docs/views/barChart/example/Gradient.vue @@ -26,6 +26,7 @@ const chartOptions = { type: 'bar', + borderRadius: 14, axesX: [{ type: 'step', }], diff --git a/docs/views/barChart/example/Horizontal.vue b/docs/views/barChart/example/Horizontal.vue index 7a3f9458d..ffa8cc9c3 100644 --- a/docs/views/barChart/example/Horizontal.vue +++ b/docs/views/barChart/example/Horizontal.vue @@ -14,7 +14,7 @@ }, labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], data: { - series1: [1500, 80, 120, 30, 0], + series1: [1500, 180, 30, 10, 0], }, }; @@ -32,6 +32,7 @@ position: 'right', }, horizontal: true, + borderRadius: 15, axesX: [{ type: 'linear', startToZero: true, diff --git a/src/components/chart/chart.core.js b/src/components/chart/chart.core.js index b14d6e6b1..4c01c4ed3 100644 --- a/src/components/chart/chart.core.js +++ b/src/components/chart/chart.core.js @@ -145,7 +145,6 @@ class EvChart { * @returns {undefined} */ drawSeries() { - const thickness = this.options.thickness; const maxTip = this.options.maxTip; const opt = { @@ -176,7 +175,8 @@ class EvChart { if (chartType === 'line' || chartType === 'scatter') { series.draw(opt); } else if (chartType === 'bar') { - series.draw({ thickness, showSeriesCount, showIndex, ...opt }); + const { thickness, borderRadius } = this.options; + series.draw({ thickness, borderRadius, showSeriesCount, showIndex, ...opt }); if (series.show) { showIndex++; diff --git a/src/components/chart/element/element.bar.js b/src/components/chart/element/element.bar.js index b0d37fe06..684439511 100644 --- a/src/components/chart/element/element.bar.js +++ b/src/components/chart/element/element.bar.js @@ -91,6 +91,9 @@ class Bar { this.size.bPad = bPad; this.size.w = w; this.size.ix = barSeriesX; + this.chartRect = chartRect; + this.labelOffset = labelOffset; + this.borderRadius = param.borderRadius; let categoryPoint = null; @@ -138,7 +141,10 @@ class Bar { ctx.fillStyle = `rgba(${Util.hexToRgb(this.color)},${opacity})` || ''; } - ctx.fillRect(x, y, w, isHorizontal ? -h : h); + this.drawBar({ + ctx, + positions: { x, y, w, h }, + }); if (showValue.use) { this.drawValueLabels({ @@ -169,7 +175,8 @@ class Bar { * @returns {undefined} */ itemHighlight(item, context) { - const { showValue, isHorizontal } = this; + const showValue = this.showValue; + const gdata = item.data; const ctx = context; @@ -184,7 +191,7 @@ class Bar { ctx.shadowBlur = 4; if (typeof this.color !== 'string') { - const grd = Canvas.createGradient(ctx, isHorizontal, { x, y, w, h }, this.color); + const grd = Canvas.createGradient(ctx, this.isHorizontal, { x, y, w, h }, this.color); ctx.fillStyle = grd; ctx.shadowColor = this.color[this.color.length - 1][1]; } else { @@ -192,7 +199,12 @@ class Bar { ctx.shadowColor = this.color; } - ctx.fillRect(x, y, w, h); + ctx.beginPath(); + + this.drawBar({ + ctx, + positions: { x, y, w, h: this.isHorizontal ? -h : h }, + }); if (showValue.use) { this.drawValueLabels({ @@ -309,6 +321,7 @@ class Bar { const ctx = context; ctx.save(); + ctx.beginPath(); const value = numberWithComma(isHorizontal ? data.x : data.y); @@ -362,6 +375,64 @@ class Bar { ctx.restore(); } + + drawBar({ ctx, positions }) { + const isHorizontal = this.isHorizontal; + const chartRect = this.chartRect; + const labelOffset = this.labelOffset; + const isStackBar = 'stackIndex' in this; + const { x, y } = positions; + let { w, h } = positions; + let r = this.borderRadius; + + // Dont's draw bar that has value 0 + if (w === 0 || h === 0) { + return; + } + + if (r && r > 0 && !isStackBar) { + const squarePath = new Path2D(); + squarePath.rect( + chartRect.x1 + labelOffset.left, + chartRect.y1, + chartRect.chartWidth - labelOffset.right, + chartRect.chartHeight - labelOffset.bottom, + ); + + ctx.clip(squarePath); + + ctx.moveTo(x, y); + + if (isHorizontal) { + if (h < r * 2) { + r = h / 2; + } + + w -= r; + ctx.lineTo(x + w, y); + ctx.arcTo(x + w + r, y, x + w + r, y - r, r); + ctx.arcTo(x + w + r, y - h, x + w, y - h, r); + ctx.lineTo(x, y - h); + ctx.lineTo(x, y); + } else { + if (w < r * 2) { + r = w / 2; + } + + h += r; + ctx.lineTo(x + w, y); + ctx.lineTo(x + w, y + h); + ctx.arcTo(x + w, y + h - r, x + w - r, y + h - r, r); + ctx.arcTo(x, y + h - r, x, y + h, r); + ctx.lineTo(x, y); + } + + ctx.fill(); + ctx.closePath(); + } else { + ctx.fillRect(x, y, w, isHorizontal ? -h : h); + } + } } export default Bar; diff --git a/src/components/chart/uses.js b/src/components/chart/uses.js index 5d9bfbc7f..c47a9717e 100644 --- a/src/components/chart/uses.js +++ b/src/components/chart/uses.js @@ -31,6 +31,7 @@ const DEFAULT_OPTIONS = { width: '100%', height: '100%', thickness: 1, + borderRadius: 0, combo: false, tooltip: { use: true,