Skip to content

Commit

Permalink
[#1130] Line Chart > Select Series (#1130)
Browse files Browse the repository at this point in the history
  • Loading branch information
baejihoon authored Apr 19, 2022
1 parent b657b4b commit 01df13b
Show file tree
Hide file tree
Showing 10 changed files with 494 additions and 37 deletions.
26 changes: 22 additions & 4 deletions docs/views/lineChart/api/lineChart.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,18 @@ const selectedLabel = ref({
});
```

### 3. data
### 3. v-model:selectedSeries
- option에서 [selectSeries](#selectseries) 옵션을 사용할 경우 유효한 바인딩
- 현재 선택된 시리즈의 ID 값의 배열 (seriesId)
- 차트 클릭이 아니라 특정 시리즈를 선택하고 싶은 경우 바인딩 하고, seriesId 배열의 값으로 차트를 컨트롤 한다.
#### Example
```
const selectedSeries = ref({
seriesId: ['series1'], // option 에 설정한 limit 갯수 까지 선택 가능.
});
```

### 4. data
| 이름 | 타입 | 디폴트 | 설명 | 종류 |
|------------ |-----------|---------|-------------------------|---------------------------------------------------|
| series | Object | {} | 특정 데이터에 대한 시리즈 옵션 | |
Expand Down Expand Up @@ -78,7 +89,7 @@ const chartData =
};
```

### 4. options
### 5. options
| 이름 | 타입 | 디폴트 | 설명 | 종류(예시) |
|------------ |-----------|---------|-------------------------|---------------------------------------------------|
| type | String | '' | series 별로 type값을 지정하지 않을 경우 일괄 적용될 차트의 타입 | 'bar', 'pie', 'line', 'scatter' |
Expand Down Expand Up @@ -245,6 +256,13 @@ const chartData =
| useApproximateValue | Boolean | false | 가까운 label을 선택 | |
| tipBackground | Hex, RGB, RGBA Code(String) | '#000000' | tip 배경색상 | |

#### selectSeries
| 이름 | 타입 | 디폴트 | 설명 | 종류(예시) |
|--------------------|-----------------------------|-----------|---------------------------------------| ----------|
| use | Boolean | false | 차트 라벨 선택 기능 | |
| limit | Number | 1 | 선택할 라벨의 최대 갯수 | |
| useDeselectOverflow | Boolean | false | limit 를 넘어 클릭 했을때 자동 deselect 를 할지 여부 | |

#### dragSelection
| 이름 | 타입 | 디폴트 | 설명 | 종류(예시) |
| --- | ---- | ----- | --- | ----------|
Expand All @@ -254,12 +272,12 @@ const chartData =
| opacity | Number | 0.65 | 선택 영역 불투명도 | 0 ~ 1 |


### 5. resize-timeout
### 6. resize-timeout
- Default : 0
- debounce 사용. 연속으로 이벤트가 발생한 경우, 마지막 이벤트가 끝난 시점을 기준으로 `주어진 시간 (resize-timeout)` 이후 콜백 실행


### 6. Event
### 7. Event
| 이름 | 파라미터 | 설명 |
|------|----------|------|
| click | selectedItem | 클릭된 series의 label, value, seriesID 값을 반환 |
Expand Down
248 changes: 248 additions & 0 deletions docs/views/lineChart/example/SelectSeries.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
<template>
<div class="case">
<ev-chart
v-model:selectedSeries="defaultSelectSeries"
:data="chartData1"
:options="chartOptions1"
@click="onClick"
/>
<ev-chart
v-model:selectedSeries="defaultSelectSeries"
:data="chartData2"
:options="chartOptions2"
@click="onClick"
/>
<div class="description">
<ev-toggle v-model="isLive" />
<span>
데이터 자동 업데이트
</span>
<br>
<br>
<ev-button
type="primary"
shape="radius"
@click="changeSelectedSeries('inc')"
>
+
</ev-button>
<ev-button
type="primary"
shape="radius"
@click="changeSelectedSeries('dec')"
>
-
</ev-button>
<span>
v-model:selectedSeries 변경
</span>
<br>
<br>
<div>
<div class="badge yellow">
v-model:selectedSeries
</div>
{{ defaultSelectSeries }}
<br>
<br>
<div class="badge yellow">
클릭 이벤트 데이터 (selected)
</div>
{{ clickedSeries }}
<br>
<br>
</div>
</div>
</div>
</template>

<script>
import { onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
import dayjs from 'dayjs';
export default {
setup() {
const chartData1 = reactive({
series: {
series1: { name: 'series#1' },
series2: { name: 'series#2' },
series3: { name: 'series#3' },
series4: { name: 'series#4' },
series5: { name: 'series#5' },
},
labels: [],
data: {
series1: [],
series2: [],
series3: [],
series4: [],
series5: [],
},
});
const chartData2 = reactive({
series: {
series1: { name: 'series1', fill: true, point: false },
series2: { name: 'series2', fill: true, point: false },
series3: { name: 'series3', fill: true, point: false },
series4: { name: 'series4', fill: true, point: false },
series5: { name: 'series5', fill: true, point: false },
},
labels: [],
groups: [['series1', 'series2', 'series3', 'series4', 'series5']],
data: {
series1: [],
series2: [],
series3: [],
series4: [],
series5: [],
},
});
const chartOptions1 = ref({
type: 'line',
width: '100%',
height: '80%',
title: {
show: false,
},
legend: {
show: true,
position: 'right',
},
axesX: [{
type: 'time',
timeFormat: 'HH:mm:ss',
interval: 'second',
}],
axesY: [{
type: 'linear',
showGrid: true,
startToZero: true,
autoScaleRatio: 0.1,
}],
selectSeries: {
use: true,
limit: 2,
useDeselectOverflow: true,
},
});
const chartOptions2 = ref({
type: 'line',
width: '100%',
height: '80%',
title: {
show: false,
},
legend: {
show: true,
position: 'right',
},
axesX: [{
type: 'time',
timeFormat: 'HH:mm:ss',
interval: 'second',
}],
axesY: [{
type: 'linear',
showGrid: true,
startToZero: true,
autoScaleRatio: 0.1,
}],
selectSeries: {
use: true,
limit: 2,
useDeselectOverflow: true,
},
});
const clickedSeries = ref();
const onClick = (e) => {
clickedSeries.value = e.selected;
};
const defaultSelectSeries = ref({
seriesId: ['series1'],
});
const changeSelectedSeries = (type) => {
const selectedList = defaultSelectSeries.value.seriesId;
let idx;
if (selectedList.length === 0) {
selectedList.push('series1');
} else {
idx = +(selectedList.pop()[6]);
if (type === 'inc') {
idx = idx < 5 ? idx + 1 : 1;
} else {
idx = idx > 1 ? idx - 1 : 5;
}
}
selectedList.push(`series${idx}`);
};
const isLive = ref(false);
const liveInterval = ref();
let timeValue = dayjs().format('YYYY-MM-DD HH:mm:ss');
const addRandomChartData = () => {
if (isLive.value) {
chartData1.labels.shift();
chartData2.labels.shift();
}
timeValue = dayjs(timeValue).add(6, 'second');
chartData1.labels.push(dayjs(timeValue));
chartData2.labels.push(dayjs(timeValue));
Object.values(chartData1.data).forEach((seriesData) => {
if (isLive.value) {
seriesData.shift();
}
seriesData.push(Math.floor(Math.random() * ((5000 - 5) + 1)) + 5);
});
Object.values(chartData2.data).forEach((seriesData) => {
if (isLive.value) {
seriesData.shift();
}
seriesData.push(Math.floor(Math.random() * ((5000 - 5) + 1)) + 5);
});
};
onMounted(() => {
for (let ix = 0; ix < 10; ix++) {
addRandomChartData();
}
});
watch(isLive, (newValue) => {
if (newValue) {
addRandomChartData();
liveInterval.value = setInterval(addRandomChartData, 6000);
} else {
clearInterval(liveInterval.value);
}
});
onBeforeUnmount(() => {
clearInterval(liveInterval.value);
});
return {
chartData1,
chartData2,
chartOptions1,
chartOptions2,
clickedSeries,
defaultSelectSeries,
isLive,
onClick,
changeSelectedSeries,
};
},
};
</script>

<style lang="scss" scoped>
.description {
position: relative;
}
</style>
7 changes: 7 additions & 0 deletions docs/views/lineChart/props.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import PlotLine from './example/PlotLine';
import PlotLineRaw from '!!raw-loader!./example/PlotLine';
import SelectLabel from './example/SelectLabel';
import SelectLabelRaw from '!!raw-loader!./example/SelectLabel';
import SelectSeries from './example/SelectSeries';
import SelectSeriesRaw from '!!raw-loader!./example/SelectSeries';

export default {
mdText,
Expand Down Expand Up @@ -45,6 +47,11 @@ export default {
component: SelectLabel,
parsedData: parseComponent(SelectLabelRaw),
},
'Select Series': {
description: '선택한 시리즈가 하이라이트 되어 보이는 기능입니다.',
component: SelectSeries,
parsedData: parseComponent(SelectSeriesRaw),
},
DragSelection: {
description: 'Drag Select 이벤트 등록이 가능 합니다',
component: DragSelection,
Expand Down
23 changes: 21 additions & 2 deletions src/components/chart/Chart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
type: Object,
default: null,
},
selectedSeries: {
type: Object,
default: null,
},
options: {
type: Object,
default: () => ({}),
Expand All @@ -43,6 +47,7 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
'drag-select',
'update:selectedItem',
'update:selectedLabel',
'update:selectedSeries',
],
setup(props) {
let evChart = {};
Expand All @@ -52,6 +57,7 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
eventListeners,
selectItemInfo,
selectLabelInfo,
selectSeriesInfo,
getNormalizedData,
getNormalizedOptions,
} = useModel();
Expand All @@ -67,13 +73,20 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
);
const createChart = () => {
let selected;
if (normalizedOptions.selectLabel.use) {
selected = selectLabelInfo;
} else if (normalizedOptions.selectSeries.use) {
selected = selectSeriesInfo;
}
evChart = new EvChart(
wrapper.value,
normalizedData,
normalizedOptions,
eventListeners,
selectItemInfo,
selectLabelInfo,
selected,
);
};
Expand Down Expand Up @@ -115,7 +128,13 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
await watch(() => props.selectedLabel, (newValue) => {
if (newValue.dataIndex) {
evChart.renderWithSelectLabel(newValue.dataIndex);
evChart.renderWithSelected(newValue.dataIndex);
}
}, { deep: true });
await watch(() => props.selectedSeries, (newValue) => {
if (newValue.seriesId) {
evChart.renderWithSelected(newValue.seriesId);
}
}, { deep: true });
});
Expand Down
Loading

0 comments on commit 01df13b

Please sign in to comment.