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
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