Api url builder fn, format data for chart.js. [WIP] Make chart work

This commit is contained in:
Pau Figueras 2023-02-08 12:53:29 +01:00
pare 8363fd950a
commit dcf8babc00
S'han modificat 5 arxius amb 155 adicions i 4 eliminacions

Veure arxiu

@ -18,5 +18,10 @@
"typescript": "^4.9.3", "typescript": "^4.9.3",
"vite": "^4.0.0" "vite": "^4.0.0"
}, },
"type": "module" "type": "module",
"dependencies": {
"chart.js": "^4.2.0",
"layercake": "^7.2.2",
"svelte-chartjs": "^3.1.2"
}
} }

Veure arxiu

@ -3,12 +3,20 @@ lockfileVersion: 5.4
specifiers: specifiers:
'@sveltejs/adapter-auto': ^1.0.0 '@sveltejs/adapter-auto': ^1.0.0
'@sveltejs/kit': ^1.0.0 '@sveltejs/kit': ^1.0.0
chart.js: ^4.2.0
layercake: ^7.2.2
svelte: ^3.54.0 svelte: ^3.54.0
svelte-chartjs: ^3.1.2
svelte-check: ^3.0.1 svelte-check: ^3.0.1
tslib: ^2.4.1 tslib: ^2.4.1
typescript: ^4.9.3 typescript: ^4.9.3
vite: ^4.0.0 vite: ^4.0.0
dependencies:
chart.js: 4.2.0
layercake: 7.2.2
svelte-chartjs: 3.1.2_sb7g7nvzgbbexijgaje6yhompe
devDependencies: devDependencies:
'@sveltejs/adapter-auto': 1.0.2_@sveltejs+kit@1.3.10 '@sveltejs/adapter-auto': 1.0.2_@sveltejs+kit@1.3.10
'@sveltejs/kit': 1.3.10_svelte@3.55.1+vite@4.1.1 '@sveltejs/kit': 1.3.10_svelte@3.55.1+vite@4.1.1
@ -234,6 +242,10 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.14 '@jridgewell/sourcemap-codec': 1.4.14
dev: true dev: true
/@kurkle/color/0.3.2:
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
dev: false
/@nodelib/fs.scandir/2.1.5: /@nodelib/fs.scandir/2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -380,6 +392,13 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true dev: true
/chart.js/4.2.0:
resolution: {integrity: sha512-wbtcV+QKeH0F7gQZaCJEIpsNriFheacouJQTVIjITi3eQA8bTlIBoknz0+dgV79aeKLNMAX+nDslIVE/nJ3rzA==}
engines: {pnpm: ^7.0.0}
dependencies:
'@kurkle/color': 0.3.2
dev: false
/chokidar/3.5.3: /chokidar/3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'} engines: {node: '>= 8.10.0'}
@ -404,6 +423,67 @@ packages:
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
dev: true dev: true
/d3-array/3.2.2:
resolution: {integrity: sha512-yEEyEAbDrF8C6Ob2myOBLjwBLck1Z89jMGFee0oPsn95GqjerpaOA4ch+vc2l0FNFFwMD5N7OCSEN5eAlsUbgQ==}
engines: {node: '>=12'}
dependencies:
internmap: 2.0.3
dev: false
/d3-color/3.1.0:
resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
engines: {node: '>=12'}
dev: false
/d3-format/3.1.0:
resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
engines: {node: '>=12'}
dev: false
/d3-interpolate/3.0.1:
resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
engines: {node: '>=12'}
dependencies:
d3-color: 3.1.0
dev: false
/d3-path/3.1.0:
resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
engines: {node: '>=12'}
dev: false
/d3-scale/4.0.2:
resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
engines: {node: '>=12'}
dependencies:
d3-array: 3.2.2
d3-format: 3.1.0
d3-interpolate: 3.0.1
d3-time: 3.1.0
d3-time-format: 4.1.0
dev: false
/d3-shape/3.2.0:
resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
engines: {node: '>=12'}
dependencies:
d3-path: 3.1.0
dev: false
/d3-time-format/4.1.0:
resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
engines: {node: '>=12'}
dependencies:
d3-time: 3.1.0
dev: false
/d3-time/3.1.0:
resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
engines: {node: '>=12'}
dependencies:
d3-array: 3.2.2
dev: false
/debug/4.3.4: /debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@ -568,6 +648,11 @@ packages:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true dev: true
/internmap/2.0.3:
resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
engines: {node: '>=12'}
dev: false
/is-binary-path/2.1.0: /is-binary-path/2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -603,6 +688,14 @@ packages:
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true dev: true
/layercake/7.2.2:
resolution: {integrity: sha512-8T5XJfJvWto7DdOAxSHRYdKd0F7smloYnOUTrCDnQ2rdRJnQlZZl9dhMU4zdeNtXfkY49Q1LUI6wAbIgduTYdw==}
dependencies:
d3-array: 3.2.2
d3-scale: 4.0.2
d3-shape: 3.2.0
dev: false
/magic-string/0.27.0: /magic-string/0.27.0:
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -828,6 +921,16 @@ packages:
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
dev: true dev: true
/svelte-chartjs/3.1.2_sb7g7nvzgbbexijgaje6yhompe:
resolution: {integrity: sha512-3+6gY2IJ9Ua8R9pk3iS1ypa7Z9OoXCJb9oPwIfTp7caJM+X+RrWnH2CTkGAq7FeSxc2nnmW08tYN88Q8Y+5M+w==}
peerDependencies:
chart.js: ^3.5.0 || ^4.0.0
svelte: ^3.45.0
dependencies:
chart.js: 4.2.0
svelte: 3.55.1
dev: false
/svelte-check/3.0.3_svelte@3.55.1: /svelte-check/3.0.3_svelte@3.55.1:
resolution: {integrity: sha512-ByBFXo3bfHRGIsYEasHkdMhLkNleVfszX/Ns1oip58tPJlKdo5Ssr8kgVIuo5oq00hss8AIcdesuy0Xt0BcTvg==} resolution: {integrity: sha512-ByBFXo3bfHRGIsYEasHkdMhLkNleVfszX/Ns1oip58tPJlKdo5Ssr8kgVIuo5oq00hss8AIcdesuy0Xt0BcTvg==}
hasBin: true hasBin: true
@ -915,7 +1018,6 @@ packages:
/svelte/3.55.1: /svelte/3.55.1:
resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==} resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
dev: true
/tiny-glob/0.2.9: /tiny-glob/0.2.9:
resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==}

Veure arxiu

@ -0,0 +1,8 @@
<script lang="ts">
import { Line } from 'svelte-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale } from 'chart.js';
ChartJS.register(Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale);
export let graphData: object = [];
</script>
<Line data={graphData} options={{ responsive: true }}></Line>

Veure arxiu

@ -4,12 +4,37 @@ let location: string = "L'Hospitalet de Llobregat";
let previousLocation: string = ''; let previousLocation: string = '';
export function load(): object { export function load(): object {
let ubicacio: Promise<string> = getFromOpenMeteo(location).then( (res) => res.results[0].name );
let temps: Promise<any> = getFromOpenMeteo(location)
.then( (res) => {
return { latitude: res.results[0].latitude, longitude: res.results[0].longitude };
})
.then( (latlon) => {
return getWeatherFromOpenMeteo(latlon.latitude, latlon.longitude);
// return [ latlon.longitude, latlon.latitude ];
})
.then( (res) => {
let forecastData: object = res.hourly;
let fmtForecastData: { labels: string[], datasets: Array<object> } = { labels: forecastData.time, datasets: [] };
let noTimeForecastData: object = Object.fromEntries(Object.entries(forecastData).filter( ([k]) => k !== 'time' ));
for (const label in noTimeForecastData) {
if (noTimeForecastData.hasOwnProperty(label)) {
const data = noTimeForecastData[label];
fmtForecastData.datasets.push({label, data})
}
}
return fmtForecastData;
} )
return { ubicacio, temps }
/**
let openMeteoData = getFromOpenMeteo(location); let openMeteoData = getFromOpenMeteo(location);
let latitude: Promise<number> = openMeteoData.then((data) => data.results[0].latitude).catch((_e) => 41.35967); let latitude: Promise<number> = openMeteoData.then((data) => data.results[0].latitude).catch((_e) => 41.35967);
let longitude: Promise<number> = openMeteoData.then((data) => data.results[0].longitude).catch((_e) => 2.10028 ); let longitude: Promise<number> = openMeteoData.then((data) => data.results[0].longitude).catch((_e) => 2.10028 );
let openMeteoWeather = getWeatherFromOpenMeteo(latitude, longitude); let openMeteoWeather = getWeatherFromOpenMeteo(latitude, longitude);
let openMeteoFetchUrl: string = openMeteoApiBase + '?latitude=' + latitude + '&logitude=' + longitude; let openMeteoFetchUrl: string = openMeteoApiBase + '?latitude=' + latitude + '&logitude=' + longitude;
return { location: openMeteoData.then( (data) => data.results[0].name ).catch( (_e) => previousLocation ), weatherData: openMeteoWeather, latitude, longitude, openMeteoFetchUrl } return { location: openMeteoData.then( (data) => data.results[0].name ).catch( (_e) => previousLocation ), weatherData: openMeteoWeather, latitude, longitude, openMeteoFetchUrl }
*/
}; };
function changeLocation(newLoc: string): void { function changeLocation(newLoc: string): void {
@ -17,6 +42,13 @@ function changeLocation(newLoc: string): void {
location = newLoc; location = newLoc;
} }
function apiUrlBuilder(apiBaseUrl: string, vars: Array<[string, string | number]>): string {
let jointVars: string[] = [];
vars.forEach( (val) => jointVars.push(`${val[0]}=${val[1]}`) );
let jointParams: string = jointVars.join('&');
return `${apiBaseUrl}?${jointParams}`;
}
export const actions = { export const actions = {
changeLoc: async ({ request }) => { changeLoc: async ({ request }) => {
const data: FormData = await request.formData(); const data: FormData = await request.formData();
@ -30,6 +62,7 @@ async function getFromOpenMeteo(ubicacio: string): Promise<any> {
} }
async function getWeatherFromOpenMeteo(latitude: any, longitude: any) { async function getWeatherFromOpenMeteo(latitude: any, longitude: any) {
let openMeteoResponse: Response = await fetch(openMeteoApiBase + '?latitude=' + latitude.toString() + '&logitude=' + longitude.toString()); // let openMeteoResponse: Response = await fetch(openMeteoApiBase + '?latitude=' + latitude + '&longitude=' + longitude);
let openMeteoResponse: Response = await fetch(apiUrlBuilder(openMeteoApiBase, [['latitude', latitude], ['longitude', longitude], ['hourly', 'temperature_2m,rain,showers,snowfall']]));
return openMeteoResponse.json() return openMeteoResponse.json()
} }

Veure arxiu

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { enhance } from "$app/forms"; import { enhance } from "$app/forms";
import Graph from "../../components/graph.svelte";
let display: string = 'none'; let display: string = 'none';
let loading: boolean = false; let loading: boolean = false;
@ -17,8 +18,10 @@
<button type="submit" disabled={loading}>Canviar</button> <button type="submit" disabled={loading}>Canviar</button>
</form> </form>
</div> </div>
<h2>Ubicació actual: { data.ubicacio }</h2>
<button type="button" on:click={toggleDisplay}>Canviar ubicació</button> <button type="button" on:click={toggleDisplay}>Canviar ubicació</button>
<pre>{ JSON.stringify(data) }</pre> <!-- <pre>{ JSON.stringify(data) }</pre> -->
<Graph graphData={data.temps} />
<footer> <footer>
<p>Dades provinents de:</p> <p>Dades provinents de:</p>
<ul> <ul>