From b8131ed7ff1150ee43fadaaf8187749df6296193 Mon Sep 17 00:00:00 2001 From: baejihoon Date: Wed, 23 Mar 2022 10:50:04 +0900 Subject: [PATCH 1/2] [#1100] Chart > Select Label --- docs/views/barChart/api/barChart.md | 13 + docs/views/barChart/example/SelectLabel.vue | 401 ++++++++++++++++++ docs/views/barChart/props.js | 7 + src/components/chart/Chart.vue | 17 +- src/components/chart/chart.core.js | 33 +- src/components/chart/element/element.bar.js | 8 +- src/components/chart/element/element.tip.js | 129 +++++- src/components/chart/model/model.store.js | 36 ++ .../chart/plugins/plugins.interaction.js | 66 ++- src/components/chart/scale/scale.js | 14 +- src/components/chart/scale/scale.step.js | 17 +- .../chart/scale/scale.time.category.js | 14 +- src/components/chart/uses.js | 20 +- 13 files changed, 746 insertions(+), 29 deletions(-) create mode 100644 docs/views/barChart/example/SelectLabel.vue diff --git a/docs/views/barChart/api/barChart.md b/docs/views/barChart/api/barChart.md index 96818aac9..14540c4e1 100644 --- a/docs/views/barChart/api/barChart.md +++ b/docs/views/barChart/api/barChart.md @@ -97,6 +97,7 @@ const chartData = { | indicator | Object | ([상세](#indicator)) | 지표선 | | | maxTip | Object | ([상세](#maxtip)) | 최대값에 tip 표시(값 표시) 여부 및 속성 | | | selectItem | Object | ([상세](#selectitem)) | 차트 아이템 선택 기능 활성화 여부 및 속성 | | + | selectLabel | Object | ([상세](#selectlabel)) | 차트 라벨 선택 기능 활성화 여부 및 속성 | | | padding | Object | { top: 20, right: 2, left: 2, bottom: 4 } | 차트 내부 padding 값 | | #### axesX axesY @@ -261,6 +262,18 @@ const chartData = { | tipBackground | Hex, RGB, RGBA Code(String) | '#000000' | tip 배경색상 | | | tipTextColor | Hex, RGB, RGBA Code(String) | '#FFFFFF' | tip 글자 색상 | | +#### selectLabel +| 이름 | 타입 | 디폴트 | 설명 | 종류(예시) | +|---------------------|-----------------------------|-----------|---------------------------------------| ----------| +| use | Boolean | false | 차트 라벨 선택 기능 | | +| limit | Number | 1 | 선택할 라벨의 최대 갯수 | | +| useDeselectOverflow | Boolean | false | limit 를 넘어 클릭 했을때 자동 deselect 를 할지 여부 | | +| showTip | Boolean | false | 선택한 위치의 Tip(화살표) 생성 여부 | | +| useSeriesOpacity | Boolean | true | 시리즈 opacity 변경 여부 | | +| useLabelOpacity | Boolean | true | 선택한 위치의 Tip(화살표) 생성 여부 | | +| fixedPosTop | Boolean | false | tip의 위치를 최대값으로 고정 | | +| useApproximateValue | Boolean | false | 가까운 label을 선택 | | +| tipBackground | Hex, RGB, RGBA Code(String) | '#000000' | tip 배경색상 | | ### 4. resize-timeout - Default : 0 diff --git a/docs/views/barChart/example/SelectLabel.vue b/docs/views/barChart/example/SelectLabel.vue new file mode 100644 index 000000000..e62017f09 --- /dev/null +++ b/docs/views/barChart/example/SelectLabel.vue @@ -0,0 +1,401 @@ + + + + + diff --git a/docs/views/barChart/props.js b/docs/views/barChart/props.js index e467b8efc..62974620e 100644 --- a/docs/views/barChart/props.js +++ b/docs/views/barChart/props.js @@ -12,6 +12,8 @@ import Time from './example/Time'; import TimeRaw from '!!raw-loader!./example/Time'; import Event from './example/Event'; import EventRaw from '!!raw-loader!./example/Event'; +import SelectLabel from './example/SelectLabel'; +import SelectLabelRaw from '!!raw-loader!./example/SelectLabel'; import Gradient from './example/Gradient'; import GradientRaw from '!!raw-loader!./example/Gradient'; import PlotLine from './example/PlotLine'; @@ -50,6 +52,11 @@ export default { component: Event, parsedData: parseComponent(EventRaw), }, + 'Select Label': { + description: '차트 전체에서 선택한 라벨 내 모든 아이템이 하이라이트 되는 기능입니다.', + component: SelectLabel, + parsedData: parseComponent(SelectLabelRaw), + }, Gradient: { description: '막대에 그라데이션 효과를 줄 수 있습니다.', component: Gradient, diff --git a/src/components/chart/Chart.vue b/src/components/chart/Chart.vue index a7212a5b4..bda2df58b 100644 --- a/src/components/chart/Chart.vue +++ b/src/components/chart/Chart.vue @@ -20,6 +20,10 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue'; type: Object, default: null, }, + selectedLabel: { + type: Object, + default: null, + }, options: { type: Object, default: () => ({}), @@ -38,6 +42,7 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue'; 'dbl-click', 'drag-select', 'update:selectedItem', + 'update:selectedLabel', ], setup(props) { let evChart = {}; @@ -45,7 +50,8 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue'; const { eventListeners, - selectInfo, + selectItemInfo, + selectLabelInfo, getNormalizedData, getNormalizedOptions, } = useModel(); @@ -66,7 +72,8 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue'; normalizedData, normalizedOptions, eventListeners, - selectInfo, + selectItemInfo, + selectLabelInfo, ); }; @@ -105,6 +112,12 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue'; const chartType = props.options?.type; evChart.selectItemByData(newValue, chartType); }, { deep: true }); + + await watch(() => props.selectedLabel, (newValue) => { + if (newValue.dataIndex) { + evChart.renderWithSelectLabel(newValue.dataIndex); + } + }, { deep: true }); }); onBeforeUnmount(() => { diff --git a/src/components/chart/chart.core.js b/src/components/chart/chart.core.js index d437dccde..5724b8bc5 100644 --- a/src/components/chart/chart.core.js +++ b/src/components/chart/chart.core.js @@ -14,7 +14,7 @@ import Pie from './plugins/plugins.pie'; import Tip from './element/element.tip'; class EvChart { - constructor(target, data, options, listeners, defaultSelectInfo) { + constructor(target, data, options, listeners, defaultSelectItemInfo, defaultSelectLabelInfo) { Object.keys(Model).forEach(key => Object.assign(this, Model[key])); Object.assign(this, Title); Object.assign(this, Legend); @@ -65,7 +65,8 @@ class EvChart { count: 0, }; - this.defaultSelectInfo = defaultSelectInfo; + this.defaultSelectItemInfo = defaultSelectItemInfo; + this.defaultSelectLabelInfo = defaultSelectLabelInfo; } /** @@ -92,6 +93,7 @@ class EvChart { this.axesRange = this.getAxesRange(); this.labelOffset = this.getLabelOffset(); + this.initSelectedLabelInfo(); this.drawChart(); @@ -146,11 +148,12 @@ class EvChart { /** * Draw each series + * @param {any} [hitInfo=undefined] from mousemove callback (object or undefined) * * @returns {undefined} */ drawSeries(hitInfo) { - const maxTip = this.options.maxTip; + const { maxTip, selectLabel } = this.options; const opt = { ctx: this.bufferCtx, @@ -158,6 +161,7 @@ class EvChart { labelOffset: this.labelOffset, axesSteps: this.axesSteps, maxTipOpt: { background: maxTip.background, color: maxTip.color }, + selectLabel: { option: selectLabel, selected: this.defaultSelectLabelInfo }, }; let showIndex = 0; @@ -189,7 +193,7 @@ class EvChart { } else { const selectInfo = hitInfo ?? this.lastHitInfo - ?? { sId: this.defaultSelectInfo?.seriesID }; + ?? { sId: this.defaultSelectItemInfo?.seriesID }; if (this.options.sunburst) { this.drawSunburst(selectInfo); @@ -207,7 +211,7 @@ class EvChart { } /** - * Draw Tip with hitInfo and defaultSelectInfo + * Draw Tip with hitInfo and defaultSelectItemInfo * @param hitInfo */ drawTip(hitInfo) { @@ -221,8 +225,8 @@ class EvChart { tipLocationInfo = hitInfo; } else if (this.lastHitInfo) { tipLocationInfo = this.lastHitInfo; - } else if (this.defaultSelectInfo) { - tipLocationInfo = this.getItem(this.defaultSelectInfo, false); + } else if (this.defaultSelectItemInfo) { + tipLocationInfo = this.getItem(this.defaultSelectItemInfo, false); } else { tipLocationInfo = null; } @@ -281,11 +285,21 @@ class EvChart { */ drawAxis(hitInfo) { this.axesX.forEach((axis, index) => { - axis.draw(this.chartRect, this.labelOffset, this.axesSteps.x[index], hitInfo); + axis.draw( + this.chartRect, + this.labelOffset, + this.axesSteps.x[index], + hitInfo, + this.defaultSelectLabelInfo); }); this.axesY.forEach((axis, index) => { - axis.draw(this.chartRect, this.labelOffset, this.axesSteps.y[index]); + axis.draw( + this.chartRect, + this.labelOffset, + this.axesSteps.y[index], + hitInfo, + this.defaultSelectLabelInfo); }); } @@ -605,6 +619,7 @@ class EvChart { this.axesY = this.createAxes('y', options.axesY); this.axesRange = this.getAxesRange(); this.labelOffset = this.getLabelOffset(); + this.initSelectedLabelInfo(); this.render(); diff --git a/src/components/chart/element/element.bar.js b/src/components/chart/element/element.bar.js index 21c747919..e5275e9ba 100644 --- a/src/components/chart/element/element.bar.js +++ b/src/components/chart/element/element.bar.js @@ -131,7 +131,13 @@ class Bar { } const barColor = item.dataColor || this.color; - const isDownplay = this.state === 'downplay'; + + const selectLabelOption = param.selectLabel.option; + const selectedLabel = param.selectLabel.selected ?? { dataIndex: [] }; + + const isDownplay = selectLabelOption.use && selectLabelOption.useSeriesOpacity + ? selectedLabel.dataIndex.length && !selectedLabel.dataIndex.includes(index) + : this.state === 'downplay'; if (typeof barColor !== 'string') { ctx.fillStyle = Canvas.createGradient( diff --git a/src/components/chart/element/element.tip.js b/src/components/chart/element/element.tip.js index cbd21a83f..7bda67934 100644 --- a/src/components/chart/element/element.tip.js +++ b/src/components/chart/element/element.tip.js @@ -14,9 +14,15 @@ const modules = { const isHorizontal = !!opt.horizontal; const maxTipOpt = opt.maxTip; const selTipOpt = opt.selectItem; + const labelTipOpt = opt.selectLabel; let maxArgs; + let isExistSelectedLabel; - if (selTipOpt.use && tipLocationInfo) { + if (labelTipOpt.use && labelTipOpt.showTip) { + isExistSelectedLabel = this.drawLabelTip(); + } + + if (selTipOpt.use && tipLocationInfo && !isExistSelectedLabel) { const seriesInfo = this.seriesList[tipLocationInfo?.sId]; if (!seriesInfo?.show) { @@ -57,8 +63,7 @@ const modules = { this.lastHitInfo = tipLocationInfo; } } - - if (maxTipOpt.use) { + if (maxTipOpt.use && !isExistSelectedLabel) { const maxSID = this.minMax[isHorizontal ? 'x' : 'y'][0].maxSID; maxArgs = this.calculateTipInfo(this.seriesList[maxSID], 'max', null); @@ -76,7 +81,8 @@ const modules = { /** * Calculate tip size and contents * @param {object} series series information (max series or selected series) - * @param {string} tipType tip type [sel = user select, max = max value] + * @param {string} tipType tip type + * [sel = user select series, label = user select label, max = max value] * @param {object} hitInfo mouse hit information * * @returns {object} size and tip contents @@ -220,6 +226,121 @@ const modules = { ctx.closePath(); }, + /** + * Draw Selected Label Tip + * @returns {boolean} Whether drew at least one tip + */ + drawLabelTip() { + const opt = this.options; + const isHorizontal = !!opt.horizontal; + const labelTipOpt = opt.selectLabel; + const { dataIndex, data } = this.defaultSelectLabelInfo; + let drawTip = false; + + if (dataIndex.length) { + drawTip = true; + + const chartRect = this.chartRect; + const labelOffset = this.labelOffset; + const aPos = { + x1: chartRect.x1 + labelOffset.left, + x2: chartRect.x2 - labelOffset.right, + y1: chartRect.y1 + labelOffset.top, + y2: chartRect.y2 - labelOffset.bottom, + }; + + const labelAxes = this.options.horizontal ? this.axesY[0] : this.axesX[0]; + const labelStartPoint = aPos[labelAxes.units.rectStart]; + const labelEndPoint = aPos[labelAxes.units.rectEnd]; + const labelGap = (labelEndPoint - labelStartPoint) / labelAxes.labels.length; + + const valueAxes = this.options.horizontal ? this.axesX[0] : this.axesY[0]; + const valueStartPoint = aPos[valueAxes.units.rectStart]; + + const offset = this.options.type === 'bar' ? 4 : 6; + const chartWidth = chartRect.chartWidth - (labelOffset.left + labelOffset.right); + const chartHeight = chartRect.chartHeight - (labelOffset.top + labelOffset.bottom); + + dataIndex.forEach((idx, i) => { + const labelCenter = Math.round(labelStartPoint + (labelGap * idx)); + let gp; + const dp = labelCenter + (labelGap / 2); + if (labelTipOpt.fixedPosTop) { + if (isHorizontal) { + gp = Canvas.calculateX( + this.axesRange.x[0].max, + this.axesRange.x[0].min, + this.axesRange.x[0].max, + chartWidth, + valueStartPoint); + gp += offset; + } else { + gp = Canvas.calculateY( + this.axesRange.y[0].max, + this.axesRange.y[0].min, + this.axesRange.y[0].max, + chartHeight, + valueStartPoint); + gp -= offset; + } + } else if (isHorizontal) { + const seriesList = Object.keys(data[i] ?? {}); + const visibleSeries = seriesList.filter(sId => this.seriesList[sId].show); + const visibleValue = visibleSeries.map(sId => data[i][sId]); + const isExistGrp = seriesList.some(sId => this.seriesList[sId].isExistGrp); + + let maxValue; + if (isExistGrp) { + maxValue = visibleValue.reduce((acc, v) => acc + v) ?? 0; + } else if (visibleValue.length) { + maxValue = Math.max(...visibleValue); + } else { + maxValue = this.axesRange.x[0].max; + } + + gp = Canvas.calculateX( + maxValue, + this.axesRange.x[0].min, + this.axesRange.x[0].max, + chartWidth, + valueStartPoint); + gp += offset; + } else { + const seriesList = Object.keys(data[i] ?? {}); + const visibleSeries = seriesList.filter(sId => this.seriesList[sId].show); + const visibleValue = visibleSeries.map(sId => data[i][sId]); + const isExistGrp = seriesList.some(sId => this.seriesList[sId].isExistGrp); + + let maxValue; + if (isExistGrp) { + maxValue = visibleValue.reduce((acc, v) => acc + v) ?? 0; + } else if (visibleValue.length) { + maxValue = Math.max(...visibleValue); + } else { + maxValue = this.axesRange.y[0].max; + } + + gp = Canvas.calculateY( + maxValue, + this.axesRange.y[0].min, + this.axesRange.y[0].max, + chartHeight, + valueStartPoint); + gp -= offset; + } + + this.showTip({ + context: this.bufferCtx, + x: isHorizontal ? gp : dp, + y: isHorizontal ? dp : gp, + opt: labelTipOpt, + isSamePos: false, + }); + }); + } + + return drawTip; + }, /** * Calculate x, y position to draw text tip * @param {object} param object for drawing text tip diff --git a/src/components/chart/model/model.store.js b/src/components/chart/model/model.store.js index 766ce2ed1..a268b8346 100644 --- a/src/components/chart/model/model.store.js +++ b/src/components/chart/model/model.store.js @@ -673,6 +673,42 @@ const modules = { }; }, + /** + * Find label info by position x and y + * @param {array} offset position x and y + * + * @returns {object} clicked label information + */ + getLabelInfoByPosition(offset) { + const [x, y] = offset; + const aPos = { + x1: this.chartRect.x1 + this.labelOffset.left, + x2: this.chartRect.x2 - this.labelOffset.right, + y1: this.chartRect.y1 + this.labelOffset.top, + y2: this.chartRect.y2 - this.labelOffset.bottom, + }; + + const scale = this.options.horizontal ? this.axesY[0] : this.axesX[0]; + const startPoint = aPos[scale.units.rectStart]; + const endPoint = aPos[scale.units.rectEnd]; + + let labelIndex; + let hitInfo; + if (scale.labels) { + const labelGap = (endPoint - startPoint) / scale.labels.length; + const index = Math.floor(((this.options.horizontal ? y : x) - startPoint) / labelGap); + labelIndex = scale.labels.length > index ? index : -1; + } else { + hitInfo = this.getItemByPosition(offset, false); + labelIndex = hitInfo.maxIndex; + } + + return { + labelIndex, + hitInfo, + }; + }, + /** * Create min/max information for all of data * @property seriesList diff --git a/src/components/chart/plugins/plugins.interaction.js b/src/components/chart/plugins/plugins.interaction.js index 063b1b85b..65103151d 100644 --- a/src/components/chart/plugins/plugins.interaction.js +++ b/src/components/chart/plugins/plugins.interaction.js @@ -1,5 +1,5 @@ import { numberWithComma } from '@/common/utils'; -import { defaultsDeep } from 'lodash-es'; +import { cloneDeep, defaultsDeep } from 'lodash-es'; const modules = { /** @@ -139,6 +139,15 @@ const modules = { } = hitInfo); } + if (this.options.selectLabel.use) { + const offset = this.getMousePosition(e); + const clickedLabelInfo = this.getLabelInfoByPosition(offset); + const selected = this.selectLabel(clickedLabelInfo.labelIndex); + this.renderWithSelectLabel(selected.dataIndex); + + args.selected = cloneDeep(this.defaultSelectLabelInfo); + } + if (typeof this.listeners.click === 'function') { if (!this.dragInfoBackup) { this.listeners.click(args); @@ -414,7 +423,7 @@ const modules = { * @returns {boolean} */ selectItemByData(targetInfo, chartType) { - this.defaultSelectInfo = targetInfo; + this.defaultSelectItemInfo = targetInfo; let foundInfo; if (chartType === 'pie') { @@ -439,6 +448,59 @@ const modules = { return true; }, + /** + * render after select label by index list + * @param indexList {array} '[0, 1 ...]' + */ + renderWithSelectLabel(indexList) { + this.defaultSelectLabelInfo.dataIndex = indexList; + this.initSelectedLabelInfo(); + this.render(); + }, + + /** + * init defaultSelectLabelInfo object. + * (set each series data and label text) + */ + initSelectedLabelInfo() { + const { use, limit } = this.options.selectLabel; + const infoObj = this.defaultSelectLabelInfo; + if (use && infoObj?.dataIndex) { + infoObj.dataIndex.splice(limit); + infoObj.label = infoObj.dataIndex.map(i => this.data.labels[i]); + const dataEntries = Object.entries(this.data.data); + infoObj.data = infoObj.dataIndex.map(labelIdx => Object.fromEntries( + dataEntries.map(([sId, data]) => [sId, data[labelIdx]]))); + } + }, + + /** + * Add or delete selected label index, according to policy and option + * (set each series data and label text) + * @param labelIndex {array} '[0, 1 ...]' + */ + selectLabel(labelIndex) { + const option = this.options?.selectLabel ?? {}; + const before = this.defaultSelectLabelInfo ?? { dataIndex: [] }; + const after = cloneDeep(before); + + if (before.dataIndex.includes(labelIndex)) { + const idx = before.dataIndex.indexOf(labelIndex); + after.dataIndex.splice(idx, 1); + } else if (labelIndex > -1) { + after.dataIndex.push(labelIndex); + if (option.limit > 0 && option.limit < after.dataIndex.length) { + if (option.useDeselectOverflow) { + after.dataIndex.splice(0, 1); + } else { + after.dataIndex.pop(); + } + } + } + + return after; + }, + /** * Find items by series within a range * @param {object} range object for find series items diff --git a/src/components/chart/scale/scale.js b/src/components/chart/scale/scale.js index 27b24e579..b566bd663 100644 --- a/src/components/chart/scale/scale.js +++ b/src/components/chart/scale/scale.js @@ -164,7 +164,7 @@ class Scale { * * @returns {undefined} */ - draw(chartRect, labelOffset, stepInfo, hitInfo) { + draw(chartRect, labelOffset, stepInfo, hitInfo, selectLabelInfo) { const ctx = this.ctx; const options = this.options; const aPos = { @@ -239,12 +239,22 @@ class Scale { linePosition = labelCenter + aliasPixel; labelText = this.getLabelFormat(Math.min(axisMax, ticks[ix])); + const isBlurredLabel = this.options?.selectLabel?.use + && this.options?.selectLabel?.useLabelOpacity + && (this.options.horizontal === (this.type === 'y')) + && selectLabelInfo?.dataIndex?.length + && !selectLabelInfo?.dataIndex?.includes(ix); + ctx.fillStyle = Util.colorStringToRgba(this.labelStyle.color, isBlurredLabel ? 0.1 : 1); + let labelPoint; if (this.type === 'x') { labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10; ctx.fillText(labelText, labelCenter, labelPoint); - if (options?.selectItem?.showLabelTip && hitInfo?.label && !this.options?.horizontal) { + if (!isBlurredLabel + && options?.selectItem?.showLabelTip + && hitInfo?.label + && !this.options?.horizontal) { const selectedLabel = this.getLabelFormat( Math.min(axisMax, hitInfo.label + (0 * stepValue)), ); diff --git a/src/components/chart/scale/scale.step.js b/src/components/chart/scale/scale.step.js index 5c41ff282..8ae7e8eba 100644 --- a/src/components/chart/scale/scale.step.js +++ b/src/components/chart/scale/scale.step.js @@ -57,7 +57,7 @@ class StepScale extends Scale { * * @returns {undefined} */ - draw(chartRect, labelOffset, stepInfo, hitInfo) { + draw(chartRect, labelOffset, stepInfo, hitInfo, selectLabelInfo) { const ctx = this.ctx; const labels = this.labels; const aPos = { @@ -121,14 +121,21 @@ class StepScale extends Scale { linePosition = labelCenter + aliasPixel; labelText = this.getLabelFormat(item, maxWidth); + const isBlurredLabel = this.options?.selectLabel?.use + && this.options?.selectLabel?.useLabelOpacity + && (this.options.horizontal === (this.type === 'y')) + && selectLabelInfo?.dataIndex?.length + && !selectLabelInfo?.dataIndex?.includes(index); + ctx.fillStyle = Util.colorStringToRgba(this.labelStyle.color, isBlurredLabel ? 0.1 : 1); + if (this.type === 'x') { labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10; ctx.fillText(labelText, labelCenter + (labelGap / 2), labelPoint); - if (this.options?.selectItem?.showLabelTip - && hitInfo?.label - && !this.options?.horizontal - ) { + if (!isBlurredLabel + && this.options?.selectItem?.showLabelTip + && hitInfo?.label + && !this.options?.horizontal) { const selectedLabel = hitInfo.label; if (selectedLabel === labelText) { const height = Math.round(ctx.measureText(this.labelStyle?.fontSize).width); diff --git a/src/components/chart/scale/scale.time.category.js b/src/components/chart/scale/scale.time.category.js index f51e6de62..506ec66e4 100644 --- a/src/components/chart/scale/scale.time.category.js +++ b/src/components/chart/scale/scale.time.category.js @@ -110,7 +110,7 @@ class TimeCategoryScale extends Scale { * * @returns {undefined} */ - draw(chartRect, labelOffset, stepInfo, hitInfo) { + draw(chartRect, labelOffset, stepInfo, hitInfo, selectLabelInfo) { const ctx = this.ctx; const labels = this.labels; const aPos = { @@ -183,12 +183,22 @@ class TimeCategoryScale extends Scale { linePosition = labelCenter + aliasPixel; labelText = this.getLabelFormat(Math.min(axisMax, ticks[ix])); + const isBlurredLabel = this.options?.selectLabel?.use + && this.options?.selectLabel?.useLabelOpacity + && (this.options.horizontal === (this.type === 'y')) + && selectLabelInfo?.dataIndex?.length + && !selectLabelInfo?.dataIndex?.includes(ix); + ctx.fillStyle = Util.colorStringToRgba(this.labelStyle.color, isBlurredLabel ? 0.1 : 1); + let labelPoint; if (this.type === 'x') { labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10; ctx.fillText(labelText, labelCenter, labelPoint); - if (this.options?.selectItem?.showLabelTip && hitInfo?.label && !this.options?.horizontal) { + if (!isBlurredLabel + && this.options?.selectItem?.showLabelTip + && hitInfo?.label + && !this.options?.horizontal) { const selectedLabel = this.getLabelFormat( Math.min(axisMax, hitInfo.label + (0 * stepValue)), ); diff --git a/src/components/chart/uses.js b/src/components/chart/uses.js index cffc89881..ab026dc72 100644 --- a/src/components/chart/uses.js +++ b/src/components/chart/uses.js @@ -82,6 +82,17 @@ const DEFAULT_OPTIONS = { tipBackground: '#000000', tipTextColor: '#FFFFFF', }, + selectLabel: { + use: false, + limit: 1, + useDeselectOverflow: false, + showTip: false, + useSeriesOpacity: true, + useLabelOpacity: true, + fixedPosTop: false, + useApproximateValue: false, + tipBackground: '#000000', + }, dragSelection: { use: false, keepDisplay: true, @@ -120,7 +131,8 @@ export const useModel = () => { }; const getNormalizedData = data => defaultsDeep(data, DEFAULT_DATA); - const selectInfo = cloneDeep(props.selectedItem); + const selectItemInfo = cloneDeep(props.selectedItem); + const selectLabelInfo = cloneDeep(props.selectedLabel); const eventListeners = { click: async (e) => { @@ -128,6 +140,9 @@ export const useModel = () => { if (e.label) { emit('update:selectedItem', { seriesID: e.seriesId, dataIndex: e.dataIndex }); } + if (e.selected) { + emit('update:selectedLabel', { dataIndex: e.selected.dataIndex }); + } emit('click', e); }, 'dbl-click': async (e) => { @@ -142,7 +157,8 @@ export const useModel = () => { return { eventListeners, - selectInfo, + selectItemInfo, + selectLabelInfo, getNormalizedData, getNormalizedOptions, }; From f74bdb8ede0b05fa65e6ca19f0c142478f9a3e30 Mon Sep 17 00:00:00 2001 From: baejihoon Date: Wed, 23 Mar 2022 16:21:27 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[#1100]=20Chart=20>=20Select=20Label=20####?= =?UTF-8?q?######=20=20-=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20ref=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/views/barChart/example/SelectLabel.vue | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/docs/views/barChart/example/SelectLabel.vue b/docs/views/barChart/example/SelectLabel.vue index e62017f09..317ad374b 100644 --- a/docs/views/barChart/example/SelectLabel.vue +++ b/docs/views/barChart/example/SelectLabel.vue @@ -1,28 +1,25 @@