diff --git a/src/charts/radarChart.ts b/src/charts/radarChart.ts index 0f274775441d0b8c1efbdbea877028c98a040955..a23edcb9b7fdf4385fa292361a456bf602c1fa03 100644 --- a/src/charts/radarChart.ts +++ b/src/charts/radarChart.ts @@ -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 diff --git a/src/main.ts b/src/main.ts index b94c63ea62505c10c75eb838453af35b8ed362ba..a96386121f2fe98af3ccdfaaeaf324f82b804251 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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 { diff --git a/src/styles/index.scss b/src/styles/index.scss index c0c8f096912c9a993708d06c24b15d57ea110e97..7b37ca49ec05f1ddd8785fe571955682d4005ad1 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -110,6 +110,11 @@ h1 { .right { flex: 1; + + #radar-chart-wrapper { + position: relative; + margin: 0 auto 4rem; + } } }