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

wip: radar chart

parent 455d570f
No related branches found
No related tags found
No related merge requests found
......@@ -6,7 +6,7 @@ export type RadarChartConfig = ChartConfig & {
selectedData: any[],
renderTooltip?: (dataPoint: any, tooltip: d3.Selection<d3.BaseType, unknown, HTMLElement, any>) => void,
axisCircles: number,
attributes: string[],
attributes: {key: string, label: string}[] | [],
}
export type RadarChartConfigParam = ChartConfigParam & Partial<RadarChartConfig>
......@@ -19,6 +19,7 @@ export default class RadarChart extends Chart {
scale: ScaleLinear<number, number>,
domain: [number, number],
label: string,
key: string,
}[] = []
constructor(data: any[], _config: RadarChartConfigParam) {
......@@ -33,7 +34,7 @@ export default class RadarChart extends Chart {
this.config = this.createConfig(_config)
}
private createConfig(_config: RadarChartConfigParam) {
private createConfig(_config: RadarChartConfigParam) : RadarChartConfig {
return {
..._config,
parentElement: typeof _config.parentElement === 'string' ? document.querySelector(_config.parentElement) as HTMLElement : _config.parentElement,
......@@ -64,16 +65,18 @@ export default class RadarChart extends Chart {
vis.chart = svg.append('g')
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(
domain,
[0, vis.chartCenter],
[0, vis.axisLength],
)
vis.axes.push({
scale,
domain,
label: attribute,
label: attribute.label,
key: attribute.key,
})
console.log(vis.axes)
}
}
......@@ -82,33 +85,51 @@ export default class RadarChart extends Chart {
const data = vis.chart.select('.dataWrapper')
this.config.selectedData = selectedData;
const preparedData = vis.config.selectedData.map((d: any) => {
return vis.axes.map(axis =>
axis.scale(d[axis.label])
)
})
const preparedData = vis.getPreparedData()
data.selectAll('.data')
.data(preparedData)
.join(
enter => enter.append("g"),
enter => enter.append("path"),
update => update,
exit => exit.remove()
)
.attr('class', 'data')
.append("path")
.attr("class", "data")
.attr("d", (d: any) => {
const data = d.map((d: any) => d.value)
return d3.lineRadial()
.angle((_, index) => Math.PI * 2 / vis.axes.length * index)
.radius((data) => data)
([...d, d[0]])
.curve(d3.curveCardinalClosed.tension(0.6))
([...data, data[0]])
})
.attr('fill', '#69b3a211')
.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() {
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 {
......@@ -118,42 +139,49 @@ export default class RadarChart extends Chart {
.attr("class", "axisWrapper")
.attr('transform', `translate(${vis.chartCenter},${vis.chartCenter})`)
axisGrid.selectAll('.axis')
const axes = axisGrid.selectAll('.axis')
.data(vis.axes)
.enter()
.append('g')
.attr('class', 'axis')
.append("path")
axes.append("path")
.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")
.attr("class", "dataWrapper")
.attr('transform', `translate(${vis.chartCenter},${vis.chartCenter})`)
const preparedData = vis.config.selectedData.map((d: any) => {
return vis.axes.map(axis =>
axis.scale(d[axis.label])
)
})
const preparedData = vis.getPreparedData()
data.selectAll('.data')
.data(preparedData)
.join(
enter => enter.append("g"),
enter => enter.append("path"),
update => update,
exit => exit.remove()
)
.attr('class', 'data')
.append("path")
.attr("class", "data")
.attr("d", (d: any) => {
const data = d.map((d: any) => d.value)
return d3.lineRadial()
.angle((_, index) => Math.PI * 2 / vis.axes.length * index)
.radius((data) => data)
([...d, d[0]])
.radius((value) => value)
.curve(d3.curveCardinalClosed.tension(0.6))
([...data, data[0]])
})
.attr('fill', '#69b3a211')
.attr('stroke', 'black')
}
}
\ No newline at end of file
......@@ -134,11 +134,36 @@ function updateSelectedNodes(node: Player) {
radarChart = new RadarChart(parsedData, {
parentElement: radarChartWrapper,
selectedData: selectedNodes,
containerWidth: 500,
containerHeight: 500,
containerWidth: 750,
containerHeight: 750,
margin: {top: 20, right: 20, bottom: 20, left: 20},
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()
} else {
......
......@@ -110,6 +110,11 @@ h1 {
.right {
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