Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
D
DV-Project
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
almohanad.hafez
DV-Project
Commits
967de113
You need to sign in or sign up before continuing.
Commit
967de113
authored
Feb 14, 2025
by
Almouhannad Hafez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add polar area chart
parent
e5e133c4
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
332 additions
and
0 deletions
+332
-0
polar-area-chart-helper.ts
src/ts/charts-helpers/polar-area-chart-helper.ts
+93
-0
polar-area-chart.ts
src/ts/charts/polar-area-chart.ts
+233
-0
main.ts
src/ts/main.ts
+6
-0
No files found.
src/ts/charts-helpers/polar-area-chart-helper.ts
0 → 100644
View file @
967de113
import
*
as
d3
from
'd3'
;
import
{
ChartConfiguration
}
from
"../chart-base/chart-configuration"
;
import
{
PolarAreaChart
}
from
'../charts/polar-area-chart'
;
export
class
PloarAreaChartHelper
{
private
container
:
any
;
private
containerId
:
string
=
'polar-area-chart-container'
;
private
svgId
:
string
=
'polar-area-chart'
;
private
selector
:
any
;
private
config
:
ChartConfiguration
=
new
ChartConfiguration
(
`#
${
this
.
svgId
}
`
,
{
width
:
500
,
height
:
408
});
private
chart
:
PolarAreaChart
;
private
data
:
any
[]
=
[];
public
setData
(
data
:
any
)
{
this
.
data
=
data
;
}
public
appendChart
()
{
// Add div container
this
.
container
=
d3
.
select
(
'#medalDistributionBySportChart'
)
.
append
(
'div'
)
.
attr
(
'class'
,
'container'
)
.
attr
(
'style'
,
'width: fit-content;'
)
.
attr
(
'id'
,
`
${
this
.
containerId
}
`
);
// Add year selector
this
.
selector
=
this
.
container
.
append
(
'div'
)
.
attr
(
'id'
,
'polar-area-chart-selector'
)
.
attr
(
'class'
,
'text-center mt-4'
);
this
.
selector
.
append
(
'label'
)
.
attr
(
'for'
,
'yearSelector'
)
.
attr
(
'class'
,
'form-label'
)
.
style
(
'font-weight'
,
'bold'
)
.
text
(
'Select year:'
);
this
.
selector
.
append
(
'select'
)
.
attr
(
'class'
,
'form-select text-center'
)
.
append
(
'option'
).
attr
(
'value'
,
'all'
).
text
(
'All years'
);
const
selectField
=
this
.
selector
.
select
(
'select'
);
const
years
=
Array
.
from
(
new
Set
(
this
.
data
.
map
(
d
=>
d
.
Year
)));
// Get unique years
years
.
forEach
(
year
=>
{
selectField
.
append
(
"option"
)
.
attr
(
"value"
,
year
)
.
text
(
year
);
});
// add select event handler
const
visHelper
=
this
;
selectField
.
on
(
"change"
,
function
(
event
:
any
)
{
const
selectedYear
=
d3
.
select
(
event
.
target
).
property
(
"value"
);
visHelper
.
updateChart
(
selectedYear
);
});
// add svg for chart
this
.
container
.
append
(
'svg'
)
.
attr
(
'id'
,
`
${
this
.
svgId
}
`
);
// init chart
this
.
chart
=
new
PolarAreaChart
(
this
.
config
);
this
.
updateChart
(
"all"
);
}
private
updateChart
(
selectedYear
:
string
)
{
// this.chart.data = this.processData(selectedYear);
this
.
chart
.
data
=
this
.
processData
(
selectedYear
);
this
.
chart
.
updateVis
();
}
private
processData
(
selectedYear
:
string
)
{
const
filteredData
=
selectedYear
!==
'all'
?
this
.
data
.
filter
(
d
=>
d
.
Year
===
selectedYear
)
:
this
.
data
;
const
sportCountMap
:
{
[
key
:
string
]:
number
}
=
{};
filteredData
.
forEach
(
d
=>
{
const
sport
=
d
.
Sport
;
if
(
sportCountMap
[
sport
])
{
sportCountMap
[
sport
]
++
;
}
else
{
sportCountMap
[
sport
]
=
1
;
}
});
const
result
:
any
[]
=
Object
.
keys
(
sportCountMap
).
map
(
key
=>
({
key
:
key
,
value
:
sportCountMap
[
key
]
}));
return
result
.
sort
((
a
,
b
)
=>
b
.
value
-
a
.
value
).
slice
(
0
,
10
);
}
}
src/ts/charts/polar-area-chart.ts
0 → 100644
View file @
967de113
import
*
as
d3
from
'd3'
;
import
{
Chart
}
from
'../chart-base/chart'
;
import
{
ChartConfiguration
}
from
'../chart-base/chart-configuration'
;
interface
PolarAreaChartDataType
{
key
:
string
;
value
:
number
;
}
export
class
PolarAreaChart
extends
Chart
{
private
pie
:
any
;
private
arc
:
any
;
private
outerArc
:
any
;
private
color
:
any
;
private
innerRadius
:
number
;
tooltip
:
d3
.
Selection
<
HTMLDivElement
,
unknown
,
HTMLElement
,
any
>
;
outerRadius
:
number
;
constructor
(
_config
:
ChartConfiguration
,
_data
?:
PolarAreaChartDataType
[])
{
super
(
_config
,
_data
);
this
.
initVis
();
}
protected
getDefaultMargins
()
{
return
{
top
:
40
,
right
:
130
,
bottom
:
20
,
left
:
130
};
}
protected
getDefaultContainerSize
()
{
return
{
width
:
500
,
height
:
500
};
}
protected
initVis
()
{
const
vis
=
this
;
// Define the pie layout
vis
.
pie
=
d3
.
pie
<
any
>
()
.
value
(
d
=>
d
.
value
)
.
sort
(
null
);
// Compute radiius
vis
.
outerRadius
=
Math
.
min
(
vis
.
width
,
vis
.
height
)
/
2
+
45
;
vis
.
innerRadius
=
vis
.
outerRadius
*
0.05
;
// Arc for the polar area chart slices
vis
.
arc
=
d3
.
arc
()
.
innerRadius
(
vis
.
innerRadius
)
.
outerRadius
((
d
:
any
)
=>
{
// Scale the outer radius based on the value
return
(
d
.
data
.
value
/
d3
.
max
(
vis
.
data
,
(
d
:
any
)
=>
d
.
value
))
*
vis
.
outerRadius
;
});
vis
.
outerArc
=
d3
.
arc
()
.
innerRadius
(
vis
.
outerRadius
*
1.1
)
// bigger than outerRadius
.
outerRadius
(
vis
.
outerRadius
*
1.1
);
// to make labels sit outside
// color scale
vis
.
color
=
d3
.
scaleOrdinal
(
d3
.
schemeCategory10
);
// tooltip
this
.
tooltip
=
d3
.
select
(
'body'
).
append
(
'div'
)
.
attr
(
'id'
,
'polar-area-chart-tooltip'
)
.
style
(
'opacity'
,
0
)
.
style
(
'position'
,
'absolute'
)
.
style
(
'display'
,
'none'
)
.
style
(
'background'
,
'white'
)
.
style
(
'border'
,
'1px solid black'
)
.
style
(
'padding'
,
'5px'
)
.
style
(
'pointer-events'
,
'none'
);
}
public
updateVis
()
{
this
.
renderVis
();
}
protected
renderVis
()
{
const
vis
=
this
;
const
totalValues
=
d3
.
sum
(
vis
.
data
,
(
d
:
any
)
=>
d
.
value
);
//helper function to find the midpoint angle
function
midAngle
(
d
:
any
)
{
return
d
.
startAngle
+
(
d
.
endAngle
-
d
.
startAngle
)
/
2
;
}
vis
.
chart
.
selectAll
(
"*"
).
remove
();
// Create group for the chart
const
g
=
vis
.
chart
.
append
(
"g"
)
.
attr
(
"transform"
,
`translate(
${
vis
.
width
/
2
}
,
${
vis
.
height
/
2
}
)`
);
// Create pie data
const
pieData
=
vis
.
pie
(
vis
.
data
);
// Bind data to group elements
const
arcs
=
g
.
selectAll
(
".arc"
)
.
data
(
pieData
,
(
d
:
any
)
=>
d
.
data
.
key
);
// ENTER
const
arcsEnter
=
arcs
.
enter
().
append
(
"g"
)
.
attr
(
"class"
,
"arc"
);
// The polar area chart slices
arcsEnter
.
append
(
"path"
)
.
attr
(
"fill"
,
(
d
:
any
)
=>
vis
.
color
(
d
.
data
.
key
))
.
attr
(
"stroke"
,
"#fff"
)
.
attr
(
"stroke-width"
,
4
)
.
attr
(
"d"
,
vis
.
arc
)
.
attr
(
"opacity"
,
0
)
.
transition
()
.
duration
(
500
)
.
attr
(
"opacity"
,
1
);
// Paths to connect slices to labels
arcsEnter
.
append
(
"path"
)
.
attr
(
"class"
,
"label-line"
)
.
attr
(
"stroke"
,
"#222"
)
.
attr
(
"stroke-width"
,
2
)
.
attr
(
"fill"
,
"none"
)
.
attr
(
"d"
,
(
d
:
any
)
=>
{
const
pos
=
vis
.
outerArc
.
centroid
(
d
);
const
mid
=
vis
.
arc
.
centroid
(
d
);
// change position based on quarter
pos
[
0
]
=
(
d
.
data
.
value
/
d3
.
max
(
vis
.
data
,
(
d
:
any
)
=>
d
.
value
))
*
vis
.
outerRadius
*
(
midAngle
(
d
)
<
Math
.
PI
?
1.2
:
-
1.2
);
return
`M
${
mid
[
0
]}
,
${
mid
[
1
]}
L
${
pos
[
0
]}
,
${
pos
[
1
]}
`
;
})
.
transition
()
.
duration
(
500
)
//labels outside the polar area chart
arcsEnter
.
append
(
"text"
)
.
attr
(
"dy"
,
"0.35em"
)
.
style
(
"font-size"
,
"12px"
)
.
style
(
"font-weight"
,
'bold'
)
.
attr
(
"text-anchor"
,
(
d
:
any
)
=>
midAngle
(
d
)
<
Math
.
PI
?
"start"
:
"end"
)
.
attr
(
"transform"
,
(
d
:
any
)
=>
{
const
[
x
,
y
]
=
vis
.
arc
.
centroid
(
d
);
return
`translate(
${
x
}
,
${
y
}
)`
;
})
.
transition
()
.
duration
(
500
)
.
attr
(
"transform"
,
(
d
:
any
)
=>
{
const
pos
=
vis
.
outerArc
.
centroid
(
d
);
pos
[
0
]
=
(
d
.
data
.
value
/
d3
.
max
(
vis
.
data
,
(
d
:
any
)
=>
d
.
value
))
*
vis
.
outerRadius
*
(
midAngle
(
d
)
<
Math
.
PI
?
1.2
:
-
1.2
)
+
(
midAngle
(
d
)
<
Math
.
PI
?
3
:
-
3
);
return
`translate(
${
pos
}
)`
;
})
.
text
((
d
:
any
)
=>
d
.
data
.
key
);
// mouse events (hover) for arcs
arcsEnter
.
select
(
"path"
)
.
on
(
"mouseover"
,
function
(
event
:
any
,
d
:
any
)
{
d3
.
select
(
event
.
currentTarget
).
attr
(
"opacity"
,
1
);
arcsEnter
.
selectAll
(
"path"
).
filter
((
arcData
:
any
)
=>
arcData
.
data
.
key
!==
d
.
data
.
key
).
attr
(
"opacity"
,
0.4
);
const
percentage
=
((
d
.
data
.
value
/
totalValues
)
*
100
).
toFixed
(
2
);
vis
.
tooltip
.
style
(
'opacity'
,
0.9
).
style
(
'display'
,
'block'
);
vis
.
tooltip
.
html
(
`
${
d
.
data
.
key
}
<br>Total Medals:
${
d
.
data
.
value
}
<br>Percentage:
${
percentage
}
%`
)
.
style
(
'left'
,
(
event
.
pageX
-
20
)
+
'px'
)
.
style
(
'top'
,
(
event
.
pageY
-
85
)
+
'px'
);
})
.
on
(
"mousemove"
,
function
(
event
:
any
)
{
vis
.
tooltip
.
style
(
'left'
,
(
event
.
pageX
-
20
)
+
'px'
)
.
style
(
'top'
,
(
event
.
pageY
-
85
)
+
'px'
);
})
.
on
(
"mouseout"
,
function
()
{
arcsEnter
.
selectAll
(
"path"
).
attr
(
"opacity"
,
1
);
vis
.
tooltip
.
style
(
'opacity'
,
0
).
style
(
'display'
,
'none'
);
});
// To make hover effect on lines also
arcsEnter
.
select
(
"path.label-line"
)
.
on
(
"mouseover"
,
function
(
event
:
any
,
d
:
any
)
{
d3
.
select
(
event
.
currentTarget
).
attr
(
"opacity"
,
1
);
arcsEnter
.
selectAll
(
"path"
).
filter
((
arcData
:
any
)
=>
arcData
.
data
.
key
!==
d
.
data
.
key
).
attr
(
"opacity"
,
0.4
);
const
percentage
=
((
d
.
data
.
value
/
totalValues
)
*
100
).
toFixed
(
2
);
vis
.
tooltip
.
style
(
'opacity'
,
0.9
).
style
(
'display'
,
'block'
);
vis
.
tooltip
.
html
(
`
${
d
.
data
.
key
}
<br>Total Medals:
${
d
.
data
.
value
}
<br>Percentage:
${
percentage
}
%`
)
.
style
(
'left'
,
(
event
.
pageX
-
20
)
+
'px'
)
.
style
(
'top'
,
(
event
.
pageY
-
85
)
+
'px'
);
})
.
on
(
"mousemove"
,
function
(
event
:
any
)
{
vis
.
tooltip
.
style
(
'left'
,
(
event
.
pageX
-
20
)
+
'px'
)
.
style
(
'top'
,
(
event
.
pageY
-
85
)
+
'px'
);
})
.
on
(
"mouseout"
,
function
()
{
arcsEnter
.
selectAll
(
"path"
).
attr
(
"opacity"
,
1
);
vis
.
tooltip
.
style
(
'opacity'
,
0
).
style
(
'display'
,
'none'
);
});
// UPDATE
arcs
.
select
(
"path"
)
.
transition
()
.
duration
(
500
)
.
attr
(
"d"
,
vis
.
arc
)
.
attr
(
"fill"
,
(
d
:
any
)
=>
vis
.
color
(
d
.
data
.
key
))
.
attr
(
"stroke"
,
"#fff"
)
.
attr
(
"stroke-width"
,
1
);
arcs
.
select
(
"path.label-line"
)
.
transition
()
.
duration
(
500
)
.
attr
(
"d"
,
(
d
:
any
)
=>
{
const
pos
=
vis
.
outerArc
.
centroid
(
d
);
const
mid
=
vis
.
arc
.
centroid
(
d
);
pos
[
0
]
=
(
d
.
data
.
value
/
d3
.
max
(
vis
.
data
,
(
d
:
any
)
=>
d
.
value
))
*
vis
.
outerRadius
*
(
midAngle
(
d
)
<
Math
.
PI
?
1.2
:
-
1.2
);
return
`M
${
mid
[
0
]}
,
${
mid
[
1
]}
L
${
pos
[
0
]}
,
${
pos
[
1
]}
`
;
});
arcs
.
select
(
"text"
)
.
transition
()
.
duration
(
500
)
.
attr
(
"text-anchor"
,
(
d
:
any
)
=>
midAngle
(
d
)
<
Math
.
PI
?
"start"
:
"end"
)
.
attr
(
"transform"
,
(
d
:
any
)
=>
{
const
pos
=
vis
.
outerArc
.
centroid
(
d
);
pos
[
0
]
=
(
d
.
data
.
value
/
d3
.
max
(
vis
.
data
,
(
d
:
any
)
=>
d
.
value
))
*
vis
.
outerRadius
*
(
midAngle
(
d
)
<
Math
.
PI
?
1.2
:
-
1.2
);
return
`translate(
${
pos
}
)`
;
})
.
text
((
d
:
any
)
=>
d
.
data
.
key
);
// EXIT
arcs
.
exit
().
remove
();
}
}
\ No newline at end of file
src/ts/main.ts
View file @
967de113
...
...
@@ -4,11 +4,14 @@ import 'bootstrap';
import
{
StackedBarChartHelper
}
from
'./charts-helpers/stacked-bar-chart-helper'
;
import
{
MultiLineChartHelper
}
from
'./charts-helpers/multi-line-chart-helper'
;
import
{
PieChartHelper
}
from
'./charts-helpers/pie-chart-helper'
;
import
{
PloarAreaChartHelper
}
from
'./charts-helpers/polar-area-chart-helper'
;
const
datasetPath
=
import
.
meta
.
env
.
VITE_DATASET_PATH
;
let
rawData
:
any
[];
const
stackerBarChartHelper
=
new
StackedBarChartHelper
();
const
multiLineChartHelper
=
new
MultiLineChartHelper
();
const
pieChartHelper
=
new
PieChartHelper
();
const
polarChartHelper
=
new
PloarAreaChartHelper
();
d3
.
csv
(
datasetPath
).
then
(
data
=>
{
rawData
=
data
.
filter
(
d
=>
d
.
Medal
!==
''
);
...
...
@@ -23,6 +26,9 @@ d3.csv(datasetPath).then(data => {
pieChartHelper
.
setData
(
rawData
);
pieChartHelper
.
appendChart
();
polarChartHelper
.
setData
(
rawData
);
polarChartHelper
.
appendChart
();
});
// Attach event listeners to buttons
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment