Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
compendium-v2
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
geant-swd
compendium-v2
Commits
76eef86e
Commit
76eef86e
authored
2 years ago
by
Bjarke Madsen
Browse files
Options
Downloads
Patches
Plain Diff
Refactor FundingSource page
parent
46192842
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
webapp/src/Schema.tsx
+7
-11
7 additions, 11 deletions
webapp/src/Schema.tsx
webapp/src/helpers/dataconversion.tsx
+102
-0
102 additions, 0 deletions
webapp/src/helpers/dataconversion.tsx
webapp/src/pages/FundingSource.tsx
+49
-197
49 additions, 197 deletions
webapp/src/pages/FundingSource.tsx
with
158 additions
and
208 deletions
webapp/src/Schema.tsx
+
7
−
11
View file @
76eef86e
...
...
@@ -27,26 +27,22 @@ export interface Budget {
}
export
interface
FundingSource
{
CLIENT_INSTITUTIONS
:
string
,
COMMERCIAL
:
string
,
EUROPEAN_FUNDING
:
string
,
GOV_PUBLIC_BODIES
:
string
,
CLIENT_INSTITUTIONS
:
number
,
COMMERCIAL
:
number
,
EUROPEAN_FUNDING
:
number
,
GOV_PUBLIC_BODIES
:
number
,
OTHER
:
number
,
NREN
:
string
,
OTHER
:
string
,
YEAR
:
number
,
id
:
number
}
export
interface
FS
{
data
:
[
FundingSource
]
}
export
interface
FundingGraphMatrix
{
export
interface
FundingSourceDataset
{
labels
:
string
[],
datasets
:
{
label
:
string
,
data
:
string
[],
data
:
number
[],
backgroundColor
:
string
borderRadius
:
number
,
borderSkipped
:
boolean
,
...
...
This diff is collapsed.
Click to expand it.
webapp/src/helpers/dataconversion.tsx
0 → 100644
+
102
−
0
View file @
76eef86e
import
{
cartesianProduct
}
from
'
cartesian-product-multiple-arrays
'
;
import
{
FundingSource
,
FundingSourceDataset
}
from
"
../Schema
"
;
const
DEFAULT_FUNDING_SOURCE_DATA
=
[
{
"
CLIENT_INSTITUTIONS
"
:
"
0.0
"
,
"
COMMERCIAL
"
:
"
0.0
"
,
"
EUROPEAN_FUNDING
"
:
"
0.0
"
,
"
GOV_PUBLIC_BODIES
"
:
"
0.0
"
,
"
NREN
"
:
""
,
"
OTHER
"
:
"
0.0
"
,
"
YEAR
"
:
0
,
"
id
"
:
0
}]
function
getColorMap
()
{
const
rgbToHex
=
(
r
:
number
,
g
:
number
,
b
:
number
)
=>
'
#
'
+
[
r
,
g
,
b
].
map
(
x
=>
{
const
hex
=
x
.
toString
(
16
)
return
hex
.
length
===
1
?
'
0
'
+
hex
:
hex
}).
join
(
''
)
let
colorMap
=
new
Map
<
string
,
string
>
();
colorMap
.
set
(
"
CLIENT INSTITUTIONS
"
,
rgbToHex
(
157
,
40
,
114
))
colorMap
.
set
(
"
COMMERCIAL
"
,
rgbToHex
(
241
,
224
,
79
))
colorMap
.
set
(
"
EUROPEAN FUNDING
"
,
rgbToHex
(
219
,
42
,
76
))
colorMap
.
set
(
"
GOV/PUBLIC_BODIES
"
,
rgbToHex
(
237
,
141
,
24
))
colorMap
.
set
(
"
OTHER
"
,
rgbToHex
(
137
,
166
,
121
))
return
colorMap
}
function
CreateDataLookup
(
data
:
FundingSource
[])
{
let
dataLookup
=
new
Map
<
string
,
Map
<
string
,
number
>>
();
data
.
forEach
((
item
:
FundingSource
)
=>
{
const
lookupKey
=
`
${
item
.
NREN
}
/
${
item
.
YEAR
}
`
let
fundingSourceMap
=
dataLookup
.
get
(
lookupKey
)
if
(
!
fundingSourceMap
)
{
fundingSourceMap
=
new
Map
<
string
,
number
>
();
}
fundingSourceMap
.
set
(
"
CLIENT INSTITUTIONS
"
,
item
.
CLIENT_INSTITUTIONS
)
fundingSourceMap
.
set
(
"
COMMERCIAL
"
,
item
.
COMMERCIAL
)
fundingSourceMap
.
set
(
"
EUROPEAN FUNDING
"
,
item
.
EUROPEAN_FUNDING
)
fundingSourceMap
.
set
(
"
GOV/PUBLIC_BODIES
"
,
item
.
GOV_PUBLIC_BODIES
)
fundingSourceMap
.
set
(
"
OTHER
"
,
item
.
OTHER
)
dataLookup
.
set
(
lookupKey
,
fundingSourceMap
)
})
return
dataLookup
}
export
const
createFundingSourceDataset
=
(
fundingSourcesData
:
FundingSource
[])
=>
{
const
data
=
fundingSourcesData
??
DEFAULT_FUNDING_SOURCE_DATA
;
const
dataLookup
=
CreateDataLookup
(
data
)
const
labelsYear
=
[...
new
Set
(
data
.
map
((
item
:
FundingSource
)
=>
item
.
YEAR
))];
const
labelsNREN
=
[...
new
Set
(
data
.
map
((
item
:
FundingSource
)
=>
item
.
NREN
))];
const
fundingSources
=
[
"
CLIENT INSTITUTIONS
"
,
"
COMMERCIAL
"
,
"
EUROPEAN FUNDING
"
,
"
GOV/PUBLIC_BODIES
"
,
"
OTHER
"
]
const
fundingSourcesPerYear
=
cartesianProduct
(
fundingSources
,
labelsYear
)
const
colorMap
=
getColorMap
();
const
fundingSourceDataset
=
fundingSourcesPerYear
.
map
(
function
([
fundingSource
,
year
])
{
const
color
=
colorMap
.
get
(
fundingSource
)
!
;
return
{
backgroundColor
:
color
,
label
:
fundingSource
+
"
(
"
+
year
+
"
)
"
,
data
:
labelsNREN
.
map
(
nren
=>
{
// ensure that the data is in the same order as the labels
const
lookupKey
=
`
${
nren
}
/
${
year
}
`
const
dataForYear
=
dataLookup
.
get
(
lookupKey
)
if
(
!
dataForYear
)
{
return
0
}
return
dataForYear
.
get
(
fundingSource
)
??
0
}),
stack
:
year
,
borderRadius
:
10
,
borderSkipped
:
false
,
barPercentage
:
0.5
,
borderWidth
:
0.5
,
categoryPercentage
:
0.8
}
})
const
dataResponse
:
FundingSourceDataset
=
{
// datasets: datasetFunding,
datasets
:
fundingSourceDataset
,
labels
:
labelsNREN
.
map
(
l
=>
l
.
toString
())
}
return
dataResponse
;
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
webapp/src/pages/FundingSource.tsx
+
49
−
197
View file @
76eef86e
import
React
,
{
ReactElement
,
useEffect
,
useState
}
from
'
react
'
;
import
{
ChartOptions
,
scales
,
Tick
}
from
'
chart.js
'
;
import
React
,
{
useEffect
,
useState
}
from
'
react
'
;
import
{
Bar
}
from
'
react-chartjs-2
'
;
import
{
c
artesianProduct
}
from
'
cartesian-product-multiple-arrays
'
;
import
{
c
reateFundingSourceDataset
}
from
"
../helpers/dataconversion
"
;
import
{
Chart
as
ChartJS
,
...
...
@@ -13,14 +12,9 @@ import {
Legend
,
}
from
'
chart.js
'
;
import
{
Budget
,
BudgetMatrix
,
DataEntrySection
,
FundingSource
,
FS
,
Funding
GraphMatrix
Funding
SourceDataset
}
from
"
../Schema
"
;
// import _default from "chart.js/dist/plugins/plugin.tooltip";
// import numbers = _default.defaults.animations.numbers;
ChartJS
.
register
(
...
...
@@ -32,15 +26,34 @@ ChartJS.register(
Legend
);
export
const
option
=
{
const
EMPTY_DATASET
=
{
datasets
:
[
{
backgroundColor
:
''
,
data
:
[],
label
:
''
,
borderRadius
:
0
,
borderSkipped
:
false
,
barPercentage
:
0
,
borderWidth
:
0
,
stack
:
'
0
'
,
categoryPercentage
:
0.5
}],
labels
:
[]
}
export
const
chartOptions
=
{
maintainAspectRatio
:
false
,
plugins
:
{
legend
:
{
display
:
false
,
labels
:
{
boxWidth
:
20
,
boxHeight
:
30
,
pointStyle
:
"
rectRounded
"
,
borderRadius
:
6
,
useBorderRadius
:
true
,
},
},
},
...
...
@@ -60,209 +73,48 @@ export const option = {
stacked
:
true
,
},
},
indexAxis
:
'
y
'
,
indexAxis
:
"
y
"
as const
};
function
FundingSourcePage
():
ReactElement
{
function
api
<
T
>
(
url
:
string
,
options
:
RequestInit
|
undefined
=
undefined
):
Promise
<
T
>
{
return
fetch
(
url
,
options
)
.
then
((
response
)
=>
{
if
(
!
response
.
ok
)
{
return
response
.
text
().
then
((
message
)
=>
{
console
.
error
(
`Failed to load datax:
${
message
}
`
,
response
.
status
);
throw
new
Error
(
"
The data could not be loaded, check the logs for details.
"
);
});
}
return
response
.
json
()
as
Promise
<
T
>
;
})
async
function
getData
():
Promise
<
FundingSource
[]
>
{
try
{
const
response
=
await
fetch
(
'
/api/funding/
'
);
return
response
.
json
();
}
catch
(
error
)
{
console
.
error
(
`Failed to load data:
${
error
}
`
);
throw
error
;
}
}
const
[
fundingMatrixResponse
,
setFundingMatrixResponse
]
=
useState
<
FundingGraphMatrix
>
();
const
[
fundingSourceResponse
,
setFundingSource
]
=
useState
<
FundingSource
[]
>
();
const
[
dataEntrySection
,
setDataEntrySection
]
=
useState
<
DataEntrySection
>
();
const
[
selectedDataEntry
,
setSelectedDataEntry
]
=
useState
<
number
>
(
0
);
function
FundingSourcePage
()
{
const
[
fundingSourceDataset
,
setDataset
]
=
useState
<
FundingSourceDataset
>
();
const
[
fundingSourceData
,
setFundingSourceData
]
=
useState
<
FundingSource
[]
>
();
useEffect
(()
=>
{
const
loadData
=
async
()
=>
{
if
(
fundingSourceResponse
==
undefined
)
{
api
<
FS
>
(
'
/api/funding/
'
,
{})
.
then
((
fundingSources
:
FS
)
=>
{
console
.
log
(
'
fundingSource:
'
,
fundingSources
)
const
entry
=
dataEntrySection
?.
items
.
find
(
i
=>
i
.
id
==
selectedDataEntry
)
console
.
log
(
selectedDataEntry
,
dataEntrySection
,
entry
)
if
(
entry
)
console
.
log
(
"
hello
"
)
// options.plugins.title.text = entry.title;
setFundingSource
(
fundingSources
.
data
)
convertToFundingSourcePerYearDataResponse
(
fundingSources
.
data
)
})
.
catch
(
error
=>
{
console
.
log
(
`Error fetching from API:
${
error
}
`
);
})
}
else
{
convertToFundingSourcePerYearDataResponse
(
fundingSourceResponse
)
}
const
_fundingData
=
await
getData
()
setFundingSourceData
(
_fundingData
)
}
loadData
()
},
[])
const
empty_funding_source_response
=
[
{
"
CLIENT_INSTITUTIONS
"
:
"
0.0
"
,
"
COMMERCIAL
"
:
"
0.0
"
,
"
EUROPEAN_FUNDING
"
:
"
0.0
"
,
"
GOV_PUBLIC_BODIES
"
:
"
0.0
"
,
"
NREN
"
:
""
,
"
OTHER
"
:
"
0.0
"
,
"
YEAR
"
:
0
,
"
id
"
:
0
}]
const
convertToFundingSourcePerYearDataResponse
=
(
fundingSourcesResponse
:
FundingSource
[])
=>
{
const
fsResponse
=
fundingSourcesResponse
!=
undefined
?
fundingSourcesResponse
:
empty_funding_source_response
;
const
labelsYear
=
[...
new
Set
(
fsResponse
.
map
((
item
:
FundingSource
)
=>
item
.
YEAR
))];
const
labelsNREN
=
[...
new
Set
(
fsResponse
.
map
((
item
:
FundingSource
)
=>
item
.
NREN
))];
const
fundingComposition
=
[
"
CLIENT INSTITUTIONS
"
,
"
COMMERCIAL
"
,
"
EUROPEAN FUNDING
"
,
"
GOV/PUBLIC_BODIES
"
,
"
OTHER
"
]
const
dataSetKey
=
cartesianProduct
(
fundingComposition
,
labelsYear
)
console
.
log
(
"
Nrens :
"
,
labelsNREN
)
console
.
log
(
"
Years :
"
,
labelsYear
)
console
.
log
(
dataSetKey
);
function
getRandomColor
()
{
const
red
=
Math
.
floor
(
Math
.
random
()
*
256
).
toString
(
16
).
padStart
(
2
,
'
0
'
);
// generates a value between 00 and ff
const
green
=
Math
.
floor
(
Math
.
random
()
*
256
).
toString
(
16
).
padStart
(
2
,
'
0
'
);
const
blue
=
Math
.
floor
(
Math
.
random
()
*
256
).
toString
(
16
).
padStart
(
2
,
'
0
'
);
return
`#
${
red
}${
green
}${
blue
}
`
;
}
const
rgbToHex
=
(
r
:
number
,
g
:
number
,
b
:
number
)
=>
'
#
'
+
[
r
,
g
,
b
].
map
(
x
=>
{
const
hex
=
x
.
toString
(
16
)
return
hex
.
length
===
1
?
'
0
'
+
hex
:
hex
}).
join
(
''
)
let
colorMap
=
new
Map
<
string
,
string
>
();
colorMap
.
set
(
"
CLIENT INSTITUTIONS
"
,
rgbToHex
(
157
,
40
,
114
))
colorMap
.
set
(
"
COMMERCIAL
"
,
rgbToHex
(
241
,
224
,
79
))
colorMap
.
set
(
"
EUROPEAN FUNDING
"
,
rgbToHex
(
219
,
42
,
76
))
colorMap
.
set
(
"
GOV/PUBLIC_BODIES
"
,
rgbToHex
(
237
,
141
,
24
))
colorMap
.
set
(
"
OTHER
"
,
rgbToHex
(
137
,
166
,
121
))
const
datasetFunding
=
dataSetKey
.
map
(
function
(
entry
)
{
// const randomColor = getRandomColor();
const
color
:
string
=
colorMap
.
get
(
entry
[
0
])
!
;
console
.
log
(
color
)
return
{
backgroundColor
:
color
,
label
:
entry
[
0
]
+
"
(
"
+
entry
[
1
]
+
"
)
"
,
//composition+year
data
:
labelsNREN
.
map
(
nren
=>
dataPerCompositionPerYear
(
entry
[
1
],
nren
,
entry
[
0
])),
stack
:
entry
[
1
],
borderRadius
:
10
,
borderSkipped
:
false
,
barPercentage
:
0.5
,
borderWidth
:
0.5
,
categoryPercentage
:
0.8
}
})
function
dataPerCompositionPerYear
(
year
:
number
,
nren
:
string
,
composition
:
string
)
{
let
compValue
=
""
fsResponse
.
find
(
function
(
entry
,
index
)
{
if
(
entry
.
YEAR
==
year
&&
entry
.
NREN
==
nren
)
{
if
(
composition
===
"
CLIENT INSTITUTIONS
"
)
compValue
=
String
(
entry
.
CLIENT_INSTITUTIONS
);
if
(
composition
===
"
COMMERCIAL
"
)
compValue
=
entry
.
COMMERCIAL
;
if
(
composition
===
"
EUROPEAN FUNDING
"
)
compValue
=
entry
.
EUROPEAN_FUNDING
;
if
(
composition
===
"
GOV/PUBLIC_BODIES
"
)
compValue
=
entry
.
GOV_PUBLIC_BODIES
;
if
(
composition
===
"
OTHER
"
)
compValue
=
entry
.
OTHER
;
}
})
console
.
log
(
compValue
)
return
compValue
;
useEffect
(()
=>
{
if
(
fundingSourceData
!=
undefined
)
{
const
dataset
=
createFundingSourceDataset
(
fundingSourceData
);
setDataset
(
dataset
);
}
console
.
log
(
datasetFunding
)
},
[
fundingSourceData
]
)
const
dataResponse
:
FundingGraphMatrix
=
{
// datasets: datasetFunding,
datasets
:
datasetFunding
,
labels
:
labelsNREN
.
map
(
l
=>
l
.
toString
())
}
setFundingMatrixResponse
(
dataResponse
);
}
const
empty_bar_response
=
{
datasets
:
[
{
backgroundColor
:
''
,
data
:
[],
label
:
''
,
borderRadius
:
0
,
borderSkipped
:
false
,
barPercentage
:
0
,
borderWidth
:
0
,
stack
:
'
0
'
,
categoryPercentage
:
0.5
}],
labels
:
[]
}
const
fundingAPIResponse
:
FundingGraphMatrix
=
fundingMatrixResponse
!==
undefined
?
fundingMatrixResponse
:
empty_bar_response
;
const
dataset
:
FundingSourceDataset
=
fundingSourceDataset
??
EMPTY_DATASET
;
return
(
<
div
className
=
'center'
>
<
div
className
=
"chart-container"
style
=
{
{
position
:
'
relative
'
,
height
:
'
300vh
'
,
'
width
'
:
'
80vw
'
}
}
>
<
h1
>
Income Source
</
h1
>
<
Bar
data
=
{
fundingAPIResponse
}
//height={200}
options
=
{
{
maintainAspectRatio
:
false
,
plugins
:
{
legend
:
{
display
:
false
,
labels
:
{
boxWidth
:
20
,
boxHeight
:
30
,
pointStyle
:
"
rectRounded
"
,
borderRadius
:
6
,
useBorderRadius
:
true
,
<
h1
>
Funding Source
</
h1
>
},
},
},
scales
:
{
x
:
{
stacked
:
true
,
ticks
:
{
callback
:
(
value
:
string
|
number
)
=>
{
if
(
typeof
value
===
'
number
'
)
{
return
value
.
toFixed
(
2
);
}
return
value
;
},
},
},
y
:
{
stacked
:
true
,
},
},
indexAxis
:
"
y
"
,
}
}
></
Bar
>
<
div
className
=
"chart-container"
style
=
{
{
'
minHeight
'
:
'
100vh
'
,
'
width
'
:
'
60vw
'
,
}
}
>
<
Bar
data
=
{
dataset
}
options
=
{
chartOptions
}
/>
</
div
>
</
div
>
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment