Skip to content

Commit

Permalink
Merge branch 'new-chart'
Browse files Browse the repository at this point in the history
  • Loading branch information
Olivier Ribiere committed Mar 28, 2024
2 parents 791ccf0 + 0f7c099 commit c5f4e9a
Show file tree
Hide file tree
Showing 20 changed files with 312 additions and 60 deletions.
File renamed without changes.
35 changes: 29 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
"dependencies": {
"@formkit/tempo": "^0.0.12",
"@types/geojson": "^7946.0.10",
"@vueform/slider": "^2.1.10",
"@vuepic/vue-datepicker": "^4.3.0",
"chart.js": "^4.4.2",
"core-js": "^3.30.1",
"d3-array": "^3.2.3",
"d3-brush": "^3.0.0",
Expand Down
6 changes: 3 additions & 3 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<div class="absolute bottom-0 flex flex-col w-full items-center bg-white md:static md:block">
<Stats/>
<KeyNumbers/>
<HistogramSlider/>
<div class="hidden lg:block"><Chart/></div>
</div>
<AppLegend/>
<VirtualVisit v-if="store.getState().virtualVisitAlreadyOpened"/>
Expand All @@ -24,11 +24,11 @@

<script lang="ts" setup>
import { store } from "./main"
import { computed, onMounted, watch } from "vue"
import { computed, onMounted } from "vue"
import AppHeader from "./components/Header.vue"
import AppLegend from "./components/MapLegend.vue"
import BaseMap from "./components/BaseMap.vue"
import HistogramSlider from "./components/HistogramSlider.vue"
import Chart from "./components/Chart.vue"
import KeyNumbers from "./components/KeyNumbers.vue"
import PopUp from "./components/PopUp.vue"
import Stats from "./components/Stats.vue"
Expand Down
13 changes: 9 additions & 4 deletions src/Store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export class Store {
virtualVisitAlreadyOpened: false,
minDate: new Date(2016, 2, 7),
maxDate: new Date(),
selectedMinDate: new Date(2016, 2, 7),
selectedMaxDate: new Date(),
switch: {
rescue: true,
transfer: true,
Expand Down Expand Up @@ -96,6 +98,7 @@ export class Store {

private dataState: DataState = reactive({
OpsData: [],
filteredOpsData: [],
otherData: {} as DataState["otherData"],
harbors: {} as FeatureCollection,
sar: {} as FeatureCollection,
Expand All @@ -114,6 +117,7 @@ export class Store {
this.dataState.sarCenters = require("./assets/resources/SAR_centers.json")
this.dataState.zones12Miles = require("./assets/resources/zones_12_miles.json")
this.dataState.OpsData = await fetchOpsData()
this.dataState.filteredOpsData = [...this.dataState.OpsData]
this.dataState.dataLoaded = true
this.updateHistogramSlider()
this.updateStats(this.dataState.OpsData)
Expand All @@ -124,9 +128,10 @@ export class Store {
}

public filterData (minDate: Date, maxDate: Date): void {
this.appState.minDate = new Date(minDate)
this.appState.maxDate = new Date(maxDate)
const timeFilteredData = this.dataState.OpsData.filter(currentOperation => this.appState.minDate <= currentOperation.date && currentOperation.date <= this.appState.maxDate)
this.appState.selectedMinDate = new Date(minDate)
this.appState.selectedMaxDate = new Date(maxDate)
const timeFilteredData = this.dataState.OpsData.filter(currentOperation => this.appState.selectedMinDate <= currentOperation.date && currentOperation.date <= this.appState.selectedMaxDate)
this.dataState.filteredOpsData = timeFilteredData
this.baseMap.updateOperationsData(timeFilteredData)
this.updateStats(timeFilteredData)
}
Expand Down Expand Up @@ -159,7 +164,7 @@ export class Store {
}

updateStats (timeFilteredData: OpsData[]): void {
updateStats(this.appState.minDate, this.appState.maxDate, timeFilteredData)
updateStats(this.appState.selectedMinDate, this.appState.selectedMaxDate, timeFilteredData)
}

toggleSwitch (switchId: keyof typeof SwitchType): void {
Expand Down
2 changes: 1 addition & 1 deletion src/classes/BaseMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MapboxGLButtonControl } from "./MapboxGLButtonControl"
import { GeoJSONSource, LngLatBounds, LngLatBoundsLike, Map, MapMouseEvent, NavigationControl, Popup } from "mapbox-gl"
import { FeatureCollection } from "geojson"
import "mapbox-gl/dist/mapbox-gl.css"
import { BaseMapPickerControl } from "./BaseMapPickerControl"
import { BaseMapPickerControl } from "../../BaseMapPickerControl"
import { opsDataToGeoJSON } from "@/utils/arrayToGeojson"
import { ref, reactive } from "vue"
import { Store } from "@/Store"
Expand Down
4 changes: 2 additions & 2 deletions src/classes/PopUpAndStats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ const setInnerText = function (elemId: string, textToAdd: string) {
}

export const updateStats = function (minDate: Date, maxDate: Date, timeFilteredData: OpsData[]): void {
setInnerText("statsMinDate", getFormattedDate(minDate))
setInnerText("statsMaxDate", getFormattedDate(maxDate))
setInnerText("statsMinDate", minDate.toLocaleDateString())
setInnerText("statsMaxDate", maxDate.toLocaleDateString())
let nbSurvivor = 0
let female = 0
let male = 0
Expand Down
3 changes: 3 additions & 0 deletions src/classes/State.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export interface ApplicationState {
virtualVisitAlreadyOpened: boolean;
minDate: Date;
maxDate: Date;
selectedMinDate: Date;
selectedMaxDate: Date;
switch: { [key in SwitchType]: boolean };
informationTooltip: {
visible: boolean;
Expand All @@ -47,6 +49,7 @@ export interface ApplicationState {

export interface DataState {
OpsData: OpsData[]
filteredOpsData: OpsData[]
otherData: {
incidents: FeatureCollection
deaths: FeatureCollection
Expand Down
137 changes: 137 additions & 0 deletions src/components/Chart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<!-- eslint-disable vue/multi-word-component-names -->
<!-- eslint-disable object-shorthand -->
<template>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
</template>

<script setup lang="ts">
import { store } from "@/main"
import { watch, computed } from "vue"
import Chart from "chart.js/auto"
import { useI18n } from "vue-i18n"
const i18nLocale = useI18n()
let mixedChart: Chart<"bar" | "line", any[], unknown> | null = null
watch(() => store.getData().filteredOpsData, () => createChart())
watch(() => i18nLocale.locale.value, () => createChart())
function createChart () {
const dataset: Record<string, any> = {}
store.getData().filteredOpsData.forEach(x => {
const month = x.date.getMonth() + 1
const year = x.date.getFullYear()
if (dataset[month + "_" + year]) {
dataset[month + "_" + year].nbObs += x.nbOps
dataset[month + "_" + year].nbSurvivor += x.nbSurvivor
} else {
dataset[month + "_" + year] = {
unitTimeValue: (year * 1000) + month,
label: `${month}/${year}`,
nbObs: x.nbOps,
nbSurvivor: x.nbSurvivor
}
}
})
let datasetArray = []
for (const key in dataset) {
datasetArray.push(dataset[key])
}
datasetArray = datasetArray.sort((a, b) => a.unitTimeValue - b.unitTimeValue)
const labels = datasetArray.map(x => x.label)
const survivors = datasetArray.map(x => x.nbSurvivor)
const operations = datasetArray.map(x => x.nbObs)
const ctx = document.getElementById("myChart")
if (mixedChart) (mixedChart as any).destroy()
mixedChart = new Chart((ctx as ChartItem), {
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
stacked: true
},
y: {
type: "linear",
display: true,
position: "left"
},
y1: {
type: "linear",
display: true,
position: "right"
}
}
},
type: "bar",
data: {
labels,
datasets: [{
type: "bar",
label: opsText.value,
data: operations,
borderColor: "#F03E1B",
backgroundColor: "#F03E1B",
yAxisID: "y",
order: 2
},
{
type: "line",
label: survivorsText.value,
data: survivors,
backgroundColor: "#1A2747",
borderColor: "#1A2747",
yAxisID: "y1",
order: 1
}
]
}
})
}
const opsText = computed(() => {
switch (i18nLocale.locale.value) {
case "en":
return "Number of operations per months"
case "fr":
return "Nombre d'opérations par mois"
case "it":
return "Numero di operazioni al mese"
case "de":
return "Anzahl der Operationen pro Monat"
default:
return "Number of operations per months"
}
})
const survivorsText = computed(() => {
switch (i18nLocale.locale.value) {
case "en":
return "Survivors per months"
case "fr":
return "Personnes rescapées par mois"
case "it":
return "Naufraghi al mese"
case "de":
return "Überlebende pro Monat"
default:
return "Survivors per months"
}
})
</script>

<style>
.chart-container{
position: absolute;
bottom: 15px;
left: 3%;
z-index: 10;
background-color: rgba(255, 255, 255, 0.7);
height: 25vh;
width: 70vw;
border-radius: 10px;
}
</style>
Loading

0 comments on commit c5f4e9a

Please sign in to comment.