Skip to content
Snippets Groups Projects
Commit 983a024c authored by Leander's avatar Leander
Browse files

wip: group accessor

parent 9455a9c6
No related branches found
No related tags found
No related merge requests found
......@@ -17,6 +17,18 @@
</div>
<div id="bubble-chart-wrapper">
</div>
<div class="bubble-chart-settings">
<div class="group-by">
<label for="group-by-setting">Gruppieren nach:</label>
<select id="group-by-setting" name="group-by-setting">
<option value="default">Keine</option>
<option value="nation">Nation</option>
<option value="pos">Position</option>
<option value="team">Team</option>
<option value="league">Liga</option>
</select>
</div>
<div id="zoom-wrapper">
<button id="zoom-out">-</button>
......@@ -24,6 +36,7 @@
<button id="zoom-in">+</button>
</div>
</div>
</div>
<div class="right">
<h2>Vergleichen</h2>
<div id="radar-chart-wrapper">
......
......@@ -41,6 +41,21 @@ export default class BubbleChart extends SearchableChart {
this.initVis()
}
set _config(_config: BubbleChartConfigParam) {
this.config = {
..._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,
groupAccessor: _config.groupAccessor || (() => 'default'),
sizeAccessor: _config.sizeAccessor || (() => 5),
colorAccessor: _config.colorAccessor || (() => null),
zoomExtent: _config.zoomExtent || [0.5, 20],
}
}
initVis() {
let vis = this;
vis.config.parentElement.innerHTML += `
......@@ -68,40 +83,47 @@ export default class BubbleChart extends SearchableChart {
}
updateVis(data: any[]): void {
this.data = data
this.data = data;
this.update()
}
renderVis(): void {
let vis: BubbleChart = this;
updateVisConfig(_config: BubbleChartConfigParam): void {
this._config = {...this.config, ..._config};
this.update()
}
/*vis.config.groupAccessor = (d: any) => {
return d['nation']
}*/
private update() {
let vis: BubbleChart = this;
const chart = vis.chart
vis.updatePackRoot()
const groupedData = d3.group(
vis.data,
(d: any) => vis.config.groupAccessor(d)
)
const node = vis.chart
.selectAll("g")
.data(vis.packRoot?.descendants())
.transition()
.duration(1000)
.attr("transform", (d: any) => `translate(${d.x},${d.y})`)
node.selectAll('circle')
.transition()
.duration(1000)
.attr('fill', (d: any) => vis.getFillForNode(d))
}
const pack = d3.pack()
.size([vis.width(), vis.height()])
.padding(2)
renderVis(): void {
let vis: BubbleChart = this;
vis.packRoot = pack((d3.hierarchy(groupedData) as HierarchyNode<any>)
.sum((d: any) => vis.config.sizeAccessor(d)))
vis.updatePackRoot()
const node = chart
const node = vis.chart
.selectAll("g")
.data(vis.packRoot.descendants())
.data(vis.packRoot?.descendants())
.join("g")
.attr("transform", (d: any) => `translate(${d.x},${d.y})`)
node
.append('circle')
.attr('fill', (d:any) => d.children ? "transparent" : 'var(--primary)')
.attr('fill', (d: any) => vis.getFillForNode(d))
.attr('stroke', 'none')
.attr('stroke-width', 2)
.attr('r', (d: any) => d.r)
......@@ -116,12 +138,13 @@ export default class BubbleChart extends SearchableChart {
.style('left', (event.layerX + vis.config.tooltipPadding) + 'px')
.style('top', (event.layerY + vis.config.tooltipPadding) + 'px')
})
.on('mouseleave', () => {
.on('mouseleave', (_: Event, d: any) => {
console.log(d.data)
d3.select('#tooltip').style('display', 'none');
})
}
renderTooltip(dataPoint: { player: string; league: string; pos: string; nation: string; team: string;}) {
private renderTooltip(dataPoint: { player: string; league: string; pos: string; nation: string; team: string; }) {
d3.select('#tooltip')
.style('display', 'block')
.html(`
......@@ -135,6 +158,31 @@ export default class BubbleChart extends SearchableChart {
`)
}
/**
* Updates the d3 hierachy pack root with the current data.
* Uses the groupAccessor and sizeAccessor to group the data.
* @private
*/
private updatePackRoot() {
const groupedData = d3.group(
this.data,
(d: any) => this.config.groupAccessor(d)
)
console.log(groupedData)
this.packRoot = d3.pack()
.size([this.width(), this.height()])
.padding(4)
(
(d3.hierarchy(groupedData) as HierarchyNode<any>)
.sum((d: any) => this.config.sizeAccessor(d))
)
}
private getFillForNode(node: HierarchyNode<any>) {
if (node.children) return "transparent"
return this.config.colorAccessor(node) ?? 'var(--primary)'
}
search(input: string): void {
if (!input) return
if (!input || !this.packRoot) return
......
import "@/styles/index.scss"; // imports the default styles
import {dsv} from "d3-fetch";
import BubbleChart from "@/charts/bubbleChart.ts";
import BubbleChart, {BubbleChartConfigParam} from "@/charts/bubbleChart.ts";
import Search from "@/search.ts";
// const radarChartWrapper = document.querySelector('#radar-chart-wrapper') as HTMLDivElement;
......@@ -20,6 +20,13 @@ zoomSlider.oninput = (event) => {
}
}
const groupBySetting = document.querySelector('#group-by-setting') as HTMLInputElement
groupBySetting.oninput = (event) => {
if (bubbleChart) {
bubbleChart.updateVisConfig({groupAccessor: (d: any) => d[event.target?.value]} as BubbleChartConfigParam)
}
}
dsv(';', 'data/output.csv').then(data => {
bubbleChart = new BubbleChart(data, {
parentElement: bubbleChartWrapper,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment