Skip to content
Snippets Groups Projects
Commit 9a4b6a85 authored by Leander's avatar Leander
Browse files

wip: radar chart

parent 46aa762b
No related branches found
No related tags found
No related merge requests found
......@@ -11,6 +11,7 @@ export type BubbleChartConfig = ChartConfig & {
zoomExtent: [number, number],
onZoom?: (event: any) => void,
renderTooltip?: (dataPoint: any, tooltip: d3.Selection<d3.BaseType, unknown, HTMLElement, any>) => void,
onClick?: (dataPoint: any) => void,
}
export type BubbleChartConfigParam = ChartConfigParam & Partial<BubbleChartConfig>
......@@ -51,6 +52,8 @@ export default class BubbleChart extends SearchableChart {
sizeAccessor: _config.sizeAccessor || (() => 5),
colorAccessor: _config.colorAccessor || (() => null),
zoomExtent: _config.zoomExtent || [0.5, 20],
renderTooltip: _config.renderTooltip || (() => null),
onClick: _config.onClick || (() => null),
}
}
......@@ -152,6 +155,9 @@ export default class BubbleChart extends SearchableChart {
.on('mouseleave', (_: Event) => {
d3.select('#tooltip').style('display', 'none');
})
.on('click', (_: any, d: any) => {
vis.config.onClick?.(d.data)
})
}
private renderGroupLabels() {
......
import * as d3 from "d3";
import {curveCardinalClosed, HierarchyNode, ScaleOrdinal, ScaleRadial, ScaleSequential} from "d3";
import Chart, {ChartConfig, ChartConfigParam} from "@/charts/chart.ts";
export type RadarChartConfig = ChartConfig & {
renderTooltip?: (dataPoint: any, tooltip: d3.Selection<d3.BaseType, unknown, HTMLElement, any>) => void,
axisCircles: number,
attributes: string[],
}
export type RadarChartConfigParam = ChartConfigParam & Partial<RadarChartConfig>
export default class RadarChart extends Chart {
chartId: string = 'radarChart';
chart: any
config: RadarChartConfig
colorScale: ScaleSequential<any> | ScaleOrdinal<any, any> | null = null
radialScale: ScaleRadial<any, any> = null
angleSlice = 0.7853981633974483
constructor(data: any[], _config: RadarChartConfigParam) {
super(data, _config as ChartConfigParam)
this.config = this.createConfig(_config)
this.initVis()
}
private setConfig(_config: RadarChartConfigParam) {
this.config = this.createConfig(_config)
}
private createConfig(_config: RadarChartConfigParam) {
return {
..._config,
parentElement: typeof _config.parentElement === 'string' ? document.querySelector(_config.parentElement) as HTMLElement : _config.parentElement,
containerWidth: _config.containerWidth || 500,
containerHeight: _config.containerHeight || 140,
margin: _config.margin || {top: 10, bottom: 30, right: 10, left: 30},
tooltipPadding: _config.tooltipPadding || 15,
axisCircles: _config.axisCircles || 2,
attributes: ['Per 90 Minutes _ G+A', 'Per 90 Minutes _ xG+xAG', 'PrgP', 'Total _ Cmp%', 'Tkl+Int', 'Touches _ Touches'],
}
}
initVis() {
let vis = this;
vis.config.parentElement.innerHTML += `
<svg id="${this.chartId}"></svg>
`;
vis.config.parentElement.innerHTML += `
<div id="tooltip"></div>
`;
const svg = d3.select(`#${this.chartId}`)
.attr('width', vis.config.containerWidth)
.attr('height', vis.config.containerHeight)
.attr('transform', `translate(${vis.config.margin.left},${vis.config.margin.top})`)
vis.chart = svg.append('g')
const domain = d3.range(0, 2 * Math.PI, vis.angleSlice)
this.radialScale = d3.scaleLinear()
.domain(domain)
.range([0, 360])
vis.updateColorScale()
}
updateVis(data: any[]): void {
this.data = data;
this.update()
}
private update() {
let vis: RadarChart = this;
}
renderVis(): void {
let vis: RadarChart = this;
const node = vis.chart
.selectAll("g")
.data(vis.data)
.join("g")
}
updateColorScale() {
}
}
\ No newline at end of file
......@@ -5,11 +5,13 @@ import Search from "@/search.ts";
import {countries} from "@/countries.ts";
import {numericColumns, Player} from "@/player.ts";
import {getPositionName} from "@/positions.ts";
import RadarChart from "@/charts/radarChart.ts";
// const radarChartWrapper = document.querySelector('#radar-chart-wrapper') as HTMLDivElement;
const radarChartWrapper = document.querySelector('#radar-chart-wrapper') as HTMLDivElement;
const bubbleChartWrapper = document.querySelector('#bubble-chart-wrapper') as HTMLDivElement;
const zoomExtent: [number, number] = [1, 5]
let bubbleChart: BubbleChart | null = null
let radarChart: RadarChart | null = null
let sliderBlocked = false
const zoomSlider = document.querySelector('#zoom-slider') as HTMLInputElement
......@@ -55,6 +57,7 @@ sizeBySetting.oninput = (event) => {
bubbleChart.updateVisConfig({sizeAccessor: (d: any) => d[event.target?.value] ?? 0} as BubbleChartConfigParam)
}
}
const selectedNodes: Player[] = []
dsv(';', 'data/output.csv').then(data => {
const parsedData = data.map((d: any) => {
......@@ -94,6 +97,9 @@ dsv(';', 'data/output.csv').then(data => {
<tr><th>Alter</th><td>${age[0]}${age[1] ? ' - ' + age[1] + ' Tage' : ''}</td></tr>
</table>
`)
},
onClick: (dataPoint: any) => {
updateSelectedNodes(dataPoint)
}
})
......@@ -114,3 +120,21 @@ function updateZoomLevel(to: '+' | '-') {
to === '+' ? bubbleChart.zoomIn() : bubbleChart.zoomOut()
}
}
function updateSelectedNodes(node: Player) {
if (selectedNodes.some(n => n.player === node.player)) {
selectedNodes.splice(selectedNodes.findIndex((n: Player) => n.player === node.player), 1)
} else {
selectedNodes.push(node)
}
if (!radarChart) {
radarChart = new RadarChart(selectedNodes, {
parentElement: radarChartWrapper,
containerWidth: 500,
containerHeight: 500,
margin: {top: 20, right: 20, bottom: 20, left: 20},
axisCircles: 2,
})
radarChart.renderVis()
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment