Skip to content
Snippets Groups Projects
Commit 104fa545 authored by Leander's avatar Leander
Browse files

wip: radar chart

parent 455d570f
Branches
No related tags found
No related merge requests found
...@@ -6,7 +6,7 @@ export type RadarChartConfig = ChartConfig & { ...@@ -6,7 +6,7 @@ export type RadarChartConfig = ChartConfig & {
selectedData: any[], selectedData: any[],
renderTooltip?: (dataPoint: any, tooltip: d3.Selection<d3.BaseType, unknown, HTMLElement, any>) => void, renderTooltip?: (dataPoint: any, tooltip: d3.Selection<d3.BaseType, unknown, HTMLElement, any>) => void,
axisCircles: number, axisCircles: number,
attributes: string[], attributes: {key: string, label: string}[] | [],
} }
export type RadarChartConfigParam = ChartConfigParam & Partial<RadarChartConfig> export type RadarChartConfigParam = ChartConfigParam & Partial<RadarChartConfig>
...@@ -19,6 +19,7 @@ export default class RadarChart extends Chart { ...@@ -19,6 +19,7 @@ export default class RadarChart extends Chart {
scale: ScaleLinear<number, number>, scale: ScaleLinear<number, number>,
domain: [number, number], domain: [number, number],
label: string, label: string,
key: string,
}[] = [] }[] = []
constructor(data: any[], _config: RadarChartConfigParam) { constructor(data: any[], _config: RadarChartConfigParam) {
...@@ -33,7 +34,7 @@ export default class RadarChart extends Chart { ...@@ -33,7 +34,7 @@ export default class RadarChart extends Chart {
this.config = this.createConfig(_config) this.config = this.createConfig(_config)
} }
private createConfig(_config: RadarChartConfigParam) { private createConfig(_config: RadarChartConfigParam) : RadarChartConfig {
return { return {
..._config, ..._config,
parentElement: typeof _config.parentElement === 'string' ? document.querySelector(_config.parentElement) as HTMLElement : _config.parentElement, parentElement: typeof _config.parentElement === 'string' ? document.querySelector(_config.parentElement) as HTMLElement : _config.parentElement,
...@@ -64,16 +65,18 @@ export default class RadarChart extends Chart { ...@@ -64,16 +65,18 @@ export default class RadarChart extends Chart {
vis.chart = svg.append('g') vis.chart = svg.append('g')
for (const attribute of vis.config.attributes) { for (const attribute of vis.config.attributes) {
const domain: [number, number] = [0, (d3.max(vis.data, (d: any) => d[attribute] as number) as number)] const domain: [number, number] = [0, (d3.max(vis.data, (d: any) => d[attribute.key] as number) as number)]
const scale = d3.scaleLinear( const scale = d3.scaleLinear(
domain, domain,
[0, vis.chartCenter], [0, vis.axisLength],
) )
vis.axes.push({ vis.axes.push({
scale, scale,
domain, domain,
label: attribute, label: attribute.label,
key: attribute.key,
}) })
console.log(vis.axes)
} }
} }
...@@ -82,33 +85,51 @@ export default class RadarChart extends Chart { ...@@ -82,33 +85,51 @@ export default class RadarChart extends Chart {
const data = vis.chart.select('.dataWrapper') const data = vis.chart.select('.dataWrapper')
this.config.selectedData = selectedData; this.config.selectedData = selectedData;
const preparedData = vis.config.selectedData.map((d: any) => { const preparedData = vis.getPreparedData()
return vis.axes.map(axis =>
axis.scale(d[axis.label])
)
})
data.selectAll('.data') data.selectAll('.data')
.data(preparedData) .data(preparedData)
.join( .join(
enter => enter.append("g"), enter => enter.append("path"),
update => update, update => update,
exit => exit.remove() exit => exit.remove()
) )
.attr('class', 'data') .attr("class", "data")
.append("path")
.attr("d", (d: any) => { .attr("d", (d: any) => {
const data = d.map((d: any) => d.value)
return d3.lineRadial() return d3.lineRadial()
.angle((_, index) => Math.PI * 2 / vis.axes.length * index) .angle((_, index) => Math.PI * 2 / vis.axes.length * index)
.radius((data) => data) .radius((data) => data)
([...d, d[0]]) .curve(d3.curveCardinalClosed.tension(0.6))
([...data, data[0]])
}) })
.attr('fill', '#69b3a211') .attr('fill', '#69b3a211')
.attr('stroke', 'black') .attr('stroke', 'black')
} }
private getPreparedData() {
return this.config.selectedData.map(
(d: any) => this.axes.map(axis => {
console.log(axis.label)
console.log(d[axis.key])
console.log(axis.scale(d[axis.key]))
return {
label: axis.label,
value: axis.scale(d[axis.key])
}
})
);
}
private get chartCenter() { private get chartCenter() {
return Math.min(this.config.containerWidth, this.config.containerWidth) / 2 return Math.min(this.config.containerWidth, this.config.containerHeight) / 2
}
private get axisLength() {
if (this.config.containerWidth < this.config.containerHeight) {
return this.width() / 2
}
return this.height() / 2
} }
renderVis(): void { renderVis(): void {
...@@ -118,42 +139,49 @@ export default class RadarChart extends Chart { ...@@ -118,42 +139,49 @@ export default class RadarChart extends Chart {
.attr("class", "axisWrapper") .attr("class", "axisWrapper")
.attr('transform', `translate(${vis.chartCenter},${vis.chartCenter})`) .attr('transform', `translate(${vis.chartCenter},${vis.chartCenter})`)
axisGrid.selectAll('.axis') const axes = axisGrid.selectAll('.axis')
.data(vis.axes) .data(vis.axes)
.enter() .enter()
.append('g') .append('g')
.attr('class', 'axis') .attr('class', 'axis')
.append("path")
axes.append("path")
.attr("d", (_: any, index: number) => d3.lineRadial() .attr("d", (_: any, index: number) => d3.lineRadial()
([[0, 0], [Math.PI * 2 * index / vis.axes.length, this.chartCenter]]) ([[0, 0], [Math.PI * 2 * index / vis.axes.length, this.axisLength]])
) )
axes.append('text')
.attr("x", (_: any, index: number) => Math.sin(2 * Math.PI * (index/vis.axes.length)) * (this.axisLength + 10))
.attr("y", (_: any, index: number) => -Math.cos(2 * Math.PI * (index/vis.axes.length)) * (this.axisLength + 10))
.attr('text-anchor', 'middle')
.attr('alignment-baseline', 'middle')
.attr('font-size', 12)
.attr('fill', 'black')
.text((d: any) => d.label)
const data = vis.chart.append("g") const data = vis.chart.append("g")
.attr("class", "dataWrapper") .attr("class", "dataWrapper")
.attr('transform', `translate(${vis.chartCenter},${vis.chartCenter})`) .attr('transform', `translate(${vis.chartCenter},${vis.chartCenter})`)
const preparedData = vis.config.selectedData.map((d: any) => { const preparedData = vis.getPreparedData()
return vis.axes.map(axis =>
axis.scale(d[axis.label])
)
})
data.selectAll('.data') data.selectAll('.data')
.data(preparedData) .data(preparedData)
.join( .join(
enter => enter.append("g"), enter => enter.append("path"),
update => update, update => update,
exit => exit.remove() exit => exit.remove()
) )
.attr('class', 'data') .attr("class", "data")
.append("path")
.attr("d", (d: any) => { .attr("d", (d: any) => {
const data = d.map((d: any) => d.value)
return d3.lineRadial() return d3.lineRadial()
.angle((_, index) => Math.PI * 2 / vis.axes.length * index) .angle((_, index) => Math.PI * 2 / vis.axes.length * index)
.radius((data) => data) .radius((value) => value)
([...d, d[0]]) .curve(d3.curveCardinalClosed.tension(0.6))
([...data, data[0]])
}) })
.attr('fill', '#69b3a211') .attr('fill', '#69b3a211')
.attr('stroke', 'black') .attr('stroke', 'black')
} }
} }
\ No newline at end of file
...@@ -134,11 +134,36 @@ function updateSelectedNodes(node: Player) { ...@@ -134,11 +134,36 @@ function updateSelectedNodes(node: Player) {
radarChart = new RadarChart(parsedData, { radarChart = new RadarChart(parsedData, {
parentElement: radarChartWrapper, parentElement: radarChartWrapper,
selectedData: selectedNodes, selectedData: selectedNodes,
containerWidth: 500, containerWidth: 750,
containerHeight: 500, containerHeight: 750,
margin: {top: 20, right: 20, bottom: 20, left: 20}, margin: {top: 20, right: 20, bottom: 20, left: 20},
axisCircles: 2, axisCircles: 2,
attributes: ['Per 90 Minutes _ G+A', 'Per 90 Minutes _ xG+xAG', 'PrgP', 'Total _ Cmp%', 'Tkl+Int', 'Touches _ Touches'] attributes: [
{
key: 'Performance _ G+A',
label: numericColumns['Performance _ G+A']
},
{
key: 'Expected_0 _ npxG+xAG',
label: numericColumns['Expected_0 _ npxG+xAG']
},
{
key: 'PrgP',
label: numericColumns['PrgP']
},
{
key: 'Total _ Cmp%',
label: numericColumns['Total _ Cmp%']
},
{
key: 'Tkl+Int',
label: numericColumns['Tkl+Int']
},
{
key: 'Touches _ Touches',
label: numericColumns['Touches _ Touches']
},
]
}) })
radarChart.renderVis() radarChart.renderVis()
} else { } else {
......
...@@ -110,6 +110,11 @@ h1 { ...@@ -110,6 +110,11 @@ h1 {
.right { .right {
flex: 1; flex: 1;
#radar-chart-wrapper {
position: relative;
margin: 0 auto 4rem;
}
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment