[Client] workout - add checkbox to select data on chart - fix #116
This commit is contained in:
parent
7d2248ec8c
commit
5201362ac4
@ -23,6 +23,7 @@
|
|||||||
{{ $t('workouts.DURATION') }}
|
{{ $t('workouts.DURATION') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="chart-legend" />
|
||||||
<LineChart
|
<LineChart
|
||||||
v-bind="lineChartProps"
|
v-bind="lineChartProps"
|
||||||
class="line-chart"
|
class="line-chart"
|
||||||
@ -55,6 +56,7 @@
|
|||||||
import { LineChart, useLineChart } from 'vue-chart-3'
|
import { LineChart, useLineChart } from 'vue-chart-3'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
import { htmlLegendPlugin } from '@/components/Workout/WorkoutChart/legend'
|
||||||
import { TUnit } from '@/types/units'
|
import { TUnit } from '@/types/units'
|
||||||
import { IUserProfile } from '@/types/user'
|
import { IUserProfile } from '@/types/user'
|
||||||
import {
|
import {
|
||||||
@ -187,11 +189,18 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
legend: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
htmlLegend: {
|
||||||
|
containerID: 'chart-legend',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
const { lineChartProps } = useLineChart({
|
const { lineChartProps } = useLineChart({
|
||||||
chartData,
|
chartData,
|
||||||
options,
|
options,
|
||||||
|
plugins: [htmlLegendPlugin],
|
||||||
})
|
})
|
||||||
|
|
||||||
function updateDisplayDistance() {
|
function updateDisplayDistance() {
|
||||||
@ -237,6 +246,33 @@
|
|||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
#chart-legend {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
font-size: 0.85em;
|
||||||
|
padding: 0 $default-padding * 0.5;
|
||||||
|
|
||||||
|
span {
|
||||||
|
border-radius: 50%;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1.5px;
|
||||||
|
height: 10px;
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-left: 2px;
|
||||||
|
width: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: $small-limit) {
|
@media screen and (max-width: $small-limit) {
|
@ -0,0 +1,63 @@
|
|||||||
|
import { Chart, LegendItem } from 'chart.js'
|
||||||
|
|
||||||
|
const getOrCreateLegendList = (id: string): HTMLUListElement => {
|
||||||
|
const legendContainer = document.getElementById(id)
|
||||||
|
if (legendContainer) {
|
||||||
|
let listContainer = legendContainer.querySelector('ul')
|
||||||
|
if (!listContainer) {
|
||||||
|
listContainer = document.createElement('ul')
|
||||||
|
legendContainer.appendChild(listContainer)
|
||||||
|
}
|
||||||
|
return listContainer
|
||||||
|
}
|
||||||
|
throw new Error('No legend container')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const htmlLegendPlugin = {
|
||||||
|
id: 'htmlLegend',
|
||||||
|
afterUpdate(
|
||||||
|
chart: Chart,
|
||||||
|
args: Record<string, unknown>,
|
||||||
|
options: Record<string, string>
|
||||||
|
): void {
|
||||||
|
const ul = getOrCreateLegendList(options.containerID)
|
||||||
|
while (ul.firstChild) {
|
||||||
|
ul.firstChild.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
const legendItems = chart.options.plugins?.legend?.labels?.generateLabels
|
||||||
|
? chart.options.plugins?.legend?.labels?.generateLabels(chart)
|
||||||
|
: []
|
||||||
|
|
||||||
|
legendItems.forEach((item: LegendItem) => {
|
||||||
|
const li = document.createElement('li')
|
||||||
|
li.onclick = () => {
|
||||||
|
chart.setDatasetVisibility(
|
||||||
|
item.datasetIndex,
|
||||||
|
!chart.isDatasetVisible(item.datasetIndex)
|
||||||
|
)
|
||||||
|
chart.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkBox = document.createElement('input')
|
||||||
|
if (checkBox) {
|
||||||
|
checkBox.type = 'checkbox'
|
||||||
|
checkBox.id = item.text
|
||||||
|
checkBox.checked = !item.hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = document.createTextNode(item.text)
|
||||||
|
|
||||||
|
const boxSpan = document.createElement('span')
|
||||||
|
if (boxSpan) {
|
||||||
|
boxSpan.style.background = `${item.fillStyle}`
|
||||||
|
boxSpan.style.borderColor = `${item.strokeStyle}`
|
||||||
|
}
|
||||||
|
|
||||||
|
li.appendChild(checkBox)
|
||||||
|
li.appendChild(text)
|
||||||
|
li.appendChild(boxSpan)
|
||||||
|
ul.appendChild(li)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
@ -52,7 +52,7 @@
|
|||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
import NotFound from '@/components/Common/NotFound.vue'
|
import NotFound from '@/components/Common/NotFound.vue'
|
||||||
import WorkoutChart from '@/components/Workout/WorkoutChart.vue'
|
import WorkoutChart from '@/components/Workout/WorkoutChart/index.vue'
|
||||||
import WorkoutDetail from '@/components/Workout/WorkoutDetail/index.vue'
|
import WorkoutDetail from '@/components/Workout/WorkoutDetail/index.vue'
|
||||||
import WorkoutNotes from '@/components/Workout/WorkoutNotes.vue'
|
import WorkoutNotes from '@/components/Workout/WorkoutNotes.vue'
|
||||||
import WorkoutSegments from '@/components/Workout/WorkoutSegments.vue'
|
import WorkoutSegments from '@/components/Workout/WorkoutSegments.vue'
|
||||||
|
Loading…
Reference in New Issue
Block a user