From c1c30fb5faab021ac1905939ee3bc7f456a9bb71 Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Tue, 25 Feb 2025 15:41:44 +0100 Subject: [PATCH 01/12] =?UTF-8?q?sql=20abfrage,=20neue=20zeile=20in=20verf?= =?UTF-8?q?=C3=BCgbarkeitsverwaltung,=20wip=20heat=20akkumulation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/taxi/availability/+page.server.ts | 60 ++++++++++++++++++++ src/routes/taxi/availability/+page.svelte | 46 ++++++++++++++- 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 9492753c8..9b0d0c177 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -5,6 +5,7 @@ import type { Actions, RequestEvent } from './$types'; import { fail } from '@sveltejs/kit'; import { msg } from '$lib/msg'; import { readInt } from '$lib/server/util/readForm'; +import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; export async function load(event) { const companyId = event.locals.session?.companyId; @@ -56,9 +57,68 @@ export async function load(event) { company.lat !== null && company.lng !== null; + // HEATMAP + const heatmapInfos = await db + .selectFrom('availability') + .innerJoin('vehicle', 'vehicle.id', 'availability.vehicle') + .where('startTime', '>', toTime.getTime()) + .where('endTime', '<', fromTime.getTime()) + .where('company', '!=', companyId) + .select(['availability.id','availability.startTime', 'availability.endTime', 'availability.vehicle', 'vehicle.company']) + .execute(); + + + type Range = { + startTime: UnixtimeMs; + endTime: UnixtimeMs; + }; + type heatinfo = { + cell: Range; + heat: number; + }; + let heatarray: heatinfo[] = []; + const split = (range: Range, size: number): Array => { + let cells: Array = []; + let prev = new Date(range.startTime); + let t = new Date(range.startTime); + t.setMinutes(t.getMinutes() + size); + for (; t.getTime() <= range.endTime; t.setMinutes(t.getMinutes() + size)) { + cells.push({ startTime: prev.getTime(), endTime: t.getTime() }); + prev = new Date(t); + } + return cells; + }; + const isAInsideB = (rangeA: Range, Bstart: UnixtimeMs, Bend: UnixtimeMs) => { + return rangeA.startTime >= Bstart && rangeA.startTime < Bend && rangeA.endTime >= Bstart && rangeA.endTime <= Bend; + }; + let range: Range = {startTime: toTime.getTime(), endTime: fromTime.getTime()}; + let hours = split(range, 60); + //let indexcount = 0; + let heatcount = 0; + for(let hour of hours) + { + let cell = split(hour, 15); + for(let onecell of cell) + { + for(let heat of heatmapInfos) + { + if(isAInsideB(onecell, heat.startTime, heat.endTime)) + { + // das ist noch falsch! ich möchte in heatarray, die cell und die heat (akkumuliert von dem if) speichern, damit ich dann in page + // sowohl die cellrange als auch die heat zahl habe + // wie muss die induzierung von heatarray aussehen? + heatarray[0] = {cell: onecell, heat: heatcount++}; // hier dann später Berechnung für gewichtete Summe einbauen + } + } + //indexcount++; + } + //indexcount++; + } + return { tours: await tours, vehicles: await vehicles, + heatarray, utcDate, companyDataComplete, companyCoordinates: companyDataComplete diff --git a/src/routes/taxi/availability/+page.svelte b/src/routes/taxi/availability/+page.svelte index 64a5634d8..cf8e82f34 100644 --- a/src/routes/taxi/availability/+page.svelte +++ b/src/routes/taxi/availability/+page.svelte @@ -28,7 +28,7 @@ import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; import type { LngLatLike } from 'maplibre-gl'; - const { data, form } = $props(); + const { data, form } = $props(); type Vehicle = NonNullable[0]; @@ -299,6 +299,13 @@ return 'bg-yellow-100'; } }; + + const heatmapColor = (cell: Range) => { + data.heatarray + + return 'bg-yellow-100'; + }; + // inklusive oder exkulisve der eigenen Verfügbarkeiten? selectionFinish()} /> @@ -395,6 +402,43 @@ {/each} {/each} + + + + {"Auslastung"} + + Eine Heatmap, die die Verfügbarkeiten der anderen Taxiunternehmer anzeigt. + Farbcodierung: ...TODO... + + + + {#each split(range, 60) as x} + + + + + {#each split(x, 15) as cell} + + {/each} + + +
+
+
+ + {/each} + {/snippet} From cf2591141ac1fbce7d185e0b337ac407e3ca7c44 Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Fri, 28 Feb 2025 13:51:07 +0100 Subject: [PATCH 02/12] heatmap, einfachster Fall fertig --- src/routes/taxi/availability/+page.server.ts | 19 +++----- src/routes/taxi/availability/+page.svelte | 46 +++++++++++++++++--- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 9b0d0c177..3ca5b78b1 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -61,12 +61,11 @@ export async function load(event) { const heatmapInfos = await db .selectFrom('availability') .innerJoin('vehicle', 'vehicle.id', 'availability.vehicle') - .where('startTime', '>', toTime.getTime()) - .where('endTime', '<', fromTime.getTime()) + .where('startTime', '<', toTime.getTime()) + .where('endTime', '>', fromTime.getTime()) .where('company', '!=', companyId) - .select(['availability.id','availability.startTime', 'availability.endTime', 'availability.vehicle', 'vehicle.company']) + .select(['availability.id','startTime', 'endTime', 'vehicle', 'vehicle.company']) .execute(); - type Range = { startTime: UnixtimeMs; @@ -91,9 +90,8 @@ export async function load(event) { const isAInsideB = (rangeA: Range, Bstart: UnixtimeMs, Bend: UnixtimeMs) => { return rangeA.startTime >= Bstart && rangeA.startTime < Bend && rangeA.endTime >= Bstart && rangeA.endTime <= Bend; }; - let range: Range = {startTime: toTime.getTime(), endTime: fromTime.getTime()}; + let range: Range = {startTime: fromTime.getTime(), endTime: toTime.getTime()}; let hours = split(range, 60); - //let indexcount = 0; let heatcount = 0; for(let hour of hours) { @@ -104,15 +102,12 @@ export async function load(event) { { if(isAInsideB(onecell, heat.startTime, heat.endTime)) { - // das ist noch falsch! ich möchte in heatarray, die cell und die heat (akkumuliert von dem if) speichern, damit ich dann in page - // sowohl die cellrange als auch die heat zahl habe - // wie muss die induzierung von heatarray aussehen? - heatarray[0] = {cell: onecell, heat: heatcount++}; // hier dann später Berechnung für gewichtete Summe einbauen + heatcount++; // hier dann später Berechnung für gewichtete Summe einbauen } } - //indexcount++; + heatarray.push({cell: onecell, heat: heatcount}); + heatcount = 0; } - //indexcount++; } return { diff --git a/src/routes/taxi/availability/+page.svelte b/src/routes/taxi/availability/+page.svelte index cf8e82f34..171b8541c 100644 --- a/src/routes/taxi/availability/+page.svelte +++ b/src/routes/taxi/availability/+page.svelte @@ -301,11 +301,46 @@ }; const heatmapColor = (cell: Range) => { - data.heatarray - - return 'bg-yellow-100'; + let max = 20; + for(let heat of data.heatarray) + { + if(heat.cell.startTime == cell.startTime && heat.cell.endTime == cell.endTime) + { + // logarithmisch für stark schwankende Werte: + //let normval = Math.floor(10 * (Math.log(heat.heat + 1)) / Math.log(max + 1)); + let normval = Math.floor((heat.heat / max) * 10); + normval = heat.heat > 0 ? Math.max(1, normval) : 0; + switch(normval) + { + case 0: + return; + case 1: + return 'bg-rose-100'; + case 2: + return 'bg-rose-200'; + case 3: + return 'bg-rose-300'; + case 4: + return 'bg-rose-400'; + case 5: + return 'bg-rose-500'; + case 6: + return 'bg-rose-600'; + case 7: + return 'bg-rose-700'; + case 8: + return 'bg-rose-800'; + case 9: + return 'bg-rose-900'; + case 10: + return 'bg-rose-950'; + default: + return; + } + } + } + return; }; - // inklusive oder exkulisve der eigenen Verfügbarkeiten? selectionFinish()} /> @@ -409,8 +444,9 @@ {"Auslastung"} + Eine Heatmap, die die Verfügbarkeiten der anderen Taxiunternehmer anzeigt. - Farbcodierung: ...TODO... + Farbcodierung: linear, [1, 10] From b89481b0f0c3633c770827d8db171c231ee9826b Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Fri, 28 Feb 2025 14:13:16 +0100 Subject: [PATCH 03/12] auslagerung split und range --- src/routes/taxi/availability/+page.server.ts | 18 +++--------------- src/routes/taxi/availability/+page.svelte | 19 ++----------------- src/routes/taxi/availability/Range.ts | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 32 deletions(-) create mode 100644 src/routes/taxi/availability/Range.ts diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 3ca5b78b1..daab37952 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -6,6 +6,9 @@ import { fail } from '@sveltejs/kit'; import { msg } from '$lib/msg'; import { readInt } from '$lib/server/util/readForm'; import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; +import type { Range } from './Range'; +import { split } from './Range'; + export async function load(event) { const companyId = event.locals.session?.companyId; @@ -67,26 +70,11 @@ export async function load(event) { .select(['availability.id','startTime', 'endTime', 'vehicle', 'vehicle.company']) .execute(); - type Range = { - startTime: UnixtimeMs; - endTime: UnixtimeMs; - }; type heatinfo = { cell: Range; heat: number; }; let heatarray: heatinfo[] = []; - const split = (range: Range, size: number): Array => { - let cells: Array = []; - let prev = new Date(range.startTime); - let t = new Date(range.startTime); - t.setMinutes(t.getMinutes() + size); - for (; t.getTime() <= range.endTime; t.setMinutes(t.getMinutes() + size)) { - cells.push({ startTime: prev.getTime(), endTime: t.getTime() }); - prev = new Date(t); - } - return cells; - }; const isAInsideB = (rangeA: Range, Bstart: UnixtimeMs, Bend: UnixtimeMs) => { return rangeA.startTime >= Bstart && rangeA.startTime < Bend && rangeA.endTime >= Bstart && rangeA.endTime <= Bend; }; diff --git a/src/routes/taxi/availability/+page.svelte b/src/routes/taxi/availability/+page.svelte index 171b8541c..5856cc07b 100644 --- a/src/routes/taxi/availability/+page.svelte +++ b/src/routes/taxi/availability/+page.svelte @@ -26,17 +26,14 @@ import type { Tours } from '$lib/server/db/getTours'; import Message from '$lib/ui/Message.svelte'; import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; + import type { Range } from './Range'; + import {split} from './Range'; import type { LngLatLike } from 'maplibre-gl'; const { data, form } = $props(); type Vehicle = NonNullable[0]; - type Range = { - startTime: UnixtimeMs; - endTime: UnixtimeMs; - }; - // === // API // --- @@ -133,18 +130,6 @@ const isAvailable = (v: Vehicle, cell: Range) => v.availability.some((a) => overlaps(a, cell)); - const split = (range: Range, size: number): Array => { - let cells: Array = []; - let prev = new Date(range.startTime); - let t = new Date(range.startTime); - t.setMinutes(t.getMinutes() + size); - for (; t.getTime() <= range.endTime; t.setMinutes(t.getMinutes() + size)) { - cells.push({ startTime: prev.getTime(), endTime: t.getTime() }); - prev = new Date(t); - } - return cells; - }; - // ========= // Selection // --------- diff --git a/src/routes/taxi/availability/Range.ts b/src/routes/taxi/availability/Range.ts new file mode 100644 index 000000000..10647f389 --- /dev/null +++ b/src/routes/taxi/availability/Range.ts @@ -0,0 +1,18 @@ +import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; + +export type Range = { + startTime: UnixtimeMs; + endTime: UnixtimeMs; +}; + +export function split(range: Range, size: number): Array { + let cells: Array = []; + let prev = new Date(range.startTime); + let t = new Date(range.startTime); + t.setMinutes(t.getMinutes() + size); + for (; t.getTime() <= range.endTime; t.setMinutes(t.getMinutes() + size)) { + cells.push({ startTime: prev.getTime(), endTime: t.getTime() }); + prev = new Date(t); + } + return cells; +}; \ No newline at end of file From 9ec5191d6d7a368b5ec6a5d0eb4b5fb685cf90de Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Fri, 28 Feb 2025 14:19:35 +0100 Subject: [PATCH 04/12] changes due to format and lint --- src/routes/taxi/availability/+page.server.ts | 34 +++--- src/routes/taxi/availability/+page.svelte | 112 +++++++++---------- src/routes/taxi/availability/Range.ts | 24 ++-- 3 files changed, 80 insertions(+), 90 deletions(-) diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index daab37952..06d9d3bf3 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -9,7 +9,6 @@ import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; import type { Range } from './Range'; import { split } from './Range'; - export async function load(event) { const companyId = event.locals.session?.companyId; if (!companyId) { @@ -62,38 +61,39 @@ export async function load(event) { // HEATMAP const heatmapInfos = await db - .selectFrom('availability') - .innerJoin('vehicle', 'vehicle.id', 'availability.vehicle') + .selectFrom('availability') + .innerJoin('vehicle', 'vehicle.id', 'availability.vehicle') .where('startTime', '<', toTime.getTime()) .where('endTime', '>', fromTime.getTime()) .where('company', '!=', companyId) - .select(['availability.id','startTime', 'endTime', 'vehicle', 'vehicle.company']) + .select(['availability.id', 'startTime', 'endTime', 'vehicle', 'vehicle.company']) .execute(); - + type heatinfo = { cell: Range; - heat: number; + heat: number; }; let heatarray: heatinfo[] = []; const isAInsideB = (rangeA: Range, Bstart: UnixtimeMs, Bend: UnixtimeMs) => { - return rangeA.startTime >= Bstart && rangeA.startTime < Bend && rangeA.endTime >= Bstart && rangeA.endTime <= Bend; + return ( + rangeA.startTime >= Bstart && + rangeA.startTime < Bend && + rangeA.endTime >= Bstart && + rangeA.endTime <= Bend + ); }; - let range: Range = {startTime: fromTime.getTime(), endTime: toTime.getTime()}; + let range: Range = { startTime: fromTime.getTime(), endTime: toTime.getTime() }; let hours = split(range, 60); let heatcount = 0; - for(let hour of hours) - { + for (let hour of hours) { let cell = split(hour, 15); - for(let onecell of cell) - { - for(let heat of heatmapInfos) - { - if(isAInsideB(onecell, heat.startTime, heat.endTime)) - { + for (let onecell of cell) { + for (let heat of heatmapInfos) { + if (isAInsideB(onecell, heat.startTime, heat.endTime)) { heatcount++; // hier dann später Berechnung für gewichtete Summe einbauen } } - heatarray.push({cell: onecell, heat: heatcount}); + heatarray.push({ cell: onecell, heat: heatcount }); heatcount = 0; } } diff --git a/src/routes/taxi/availability/+page.svelte b/src/routes/taxi/availability/+page.svelte index 5856cc07b..316f89c7c 100644 --- a/src/routes/taxi/availability/+page.svelte +++ b/src/routes/taxi/availability/+page.svelte @@ -27,10 +27,10 @@ import Message from '$lib/ui/Message.svelte'; import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; import type { Range } from './Range'; - import {split} from './Range'; + import { split } from './Range'; import type { LngLatLike } from 'maplibre-gl'; - const { data, form } = $props(); + const { data, form } = $props(); type Vehicle = NonNullable[0]; @@ -286,41 +286,38 @@ }; const heatmapColor = (cell: Range) => { - let max = 20; - for(let heat of data.heatarray) - { - if(heat.cell.startTime == cell.startTime && heat.cell.endTime == cell.endTime) - { + let max = 20; + for (let heat of data.heatarray) { + if (heat.cell.startTime == cell.startTime && heat.cell.endTime == cell.endTime) { // logarithmisch für stark schwankende Werte: //let normval = Math.floor(10 * (Math.log(heat.heat + 1)) / Math.log(max + 1)); let normval = Math.floor((heat.heat / max) * 10); normval = heat.heat > 0 ? Math.max(1, normval) : 0; - switch(normval) - { - case 0: - return; - case 1: - return 'bg-rose-100'; - case 2: + switch (normval) { + case 0: + return; + case 1: + return 'bg-rose-100'; + case 2: return 'bg-rose-200'; - case 3: - return 'bg-rose-300'; - case 4: + case 3: + return 'bg-rose-300'; + case 4: return 'bg-rose-400'; - case 5: - return 'bg-rose-500'; - case 6: + case 5: + return 'bg-rose-500'; + case 6: return 'bg-rose-600'; - case 7: - return 'bg-rose-700'; - case 8: + case 7: + return 'bg-rose-700'; + case 8: return 'bg-rose-800'; - case 9: - return 'bg-rose-900'; + case 9: + return 'bg-rose-900'; case 10: - return 'bg-rose-950'; - default: - return; + return 'bg-rose-950'; + default: + return; } } } @@ -426,40 +423,33 @@ - - {"Auslastung"} - - - Eine Heatmap, die die Verfügbarkeiten der anderen Taxiunternehmer anzeigt. - Farbcodierung: linear, [1, 10] - - + + {'Auslastung'} + + + Eine Heatmap, die die Verfügbarkeiten der anderen Taxiunternehmer anzeigt. Farbcodierung: + linear, [1, 10] + + - {#each split(range, 60) as x} - - - - - {#each split(x, 15) as cell} - - {/each} - - -
-
-
- - {/each} - + {#each split(range, 60) as x} + + + + + {#each split(x, 15) as cell} + + {/each} + + +
+
+
+ + {/each} + {/snippet} diff --git a/src/routes/taxi/availability/Range.ts b/src/routes/taxi/availability/Range.ts index 10647f389..bae18103f 100644 --- a/src/routes/taxi/availability/Range.ts +++ b/src/routes/taxi/availability/Range.ts @@ -1,18 +1,18 @@ import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; export type Range = { - startTime: UnixtimeMs; - endTime: UnixtimeMs; + startTime: UnixtimeMs; + endTime: UnixtimeMs; }; export function split(range: Range, size: number): Array { - let cells: Array = []; - let prev = new Date(range.startTime); - let t = new Date(range.startTime); - t.setMinutes(t.getMinutes() + size); - for (; t.getTime() <= range.endTime; t.setMinutes(t.getMinutes() + size)) { - cells.push({ startTime: prev.getTime(), endTime: t.getTime() }); - prev = new Date(t); - } - return cells; -}; \ No newline at end of file + let cells: Array = []; + let prev = new Date(range.startTime); + let t = new Date(range.startTime); + t.setMinutes(t.getMinutes() + size); + for (; t.getTime() <= range.endTime; t.setMinutes(t.getMinutes() + size)) { + cells.push({ startTime: prev.getTime(), endTime: t.getTime() }); + prev = new Date(t); + } + return cells; +} From afb42cccbe983c03a4b6adf694bc288c96d6010c Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Fri, 28 Feb 2025 14:36:41 +0100 Subject: [PATCH 05/12] changes due to check --- src/routes/taxi/availability/+page.server.ts | 14 +++++++------- src/routes/taxi/availability/Range.ts | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 06d9d3bf3..eb853ac40 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -73,7 +73,7 @@ export async function load(event) { cell: Range; heat: number; }; - let heatarray: heatinfo[] = []; + const heatarray: heatinfo[] = []; const isAInsideB = (rangeA: Range, Bstart: UnixtimeMs, Bend: UnixtimeMs) => { return ( rangeA.startTime >= Bstart && @@ -82,13 +82,13 @@ export async function load(event) { rangeA.endTime <= Bend ); }; - let range: Range = { startTime: fromTime.getTime(), endTime: toTime.getTime() }; - let hours = split(range, 60); + const range: Range = { startTime: fromTime.getTime(), endTime: toTime.getTime() }; + const hours = split(range, 60); let heatcount = 0; - for (let hour of hours) { - let cell = split(hour, 15); - for (let onecell of cell) { - for (let heat of heatmapInfos) { + for (const hour of hours) { + const cell = split(hour, 15); + for (const onecell of cell) { + for (const heat of heatmapInfos) { if (isAInsideB(onecell, heat.startTime, heat.endTime)) { heatcount++; // hier dann später Berechnung für gewichtete Summe einbauen } diff --git a/src/routes/taxi/availability/Range.ts b/src/routes/taxi/availability/Range.ts index bae18103f..b8a8aaf9f 100644 --- a/src/routes/taxi/availability/Range.ts +++ b/src/routes/taxi/availability/Range.ts @@ -6,9 +6,9 @@ export type Range = { }; export function split(range: Range, size: number): Array { - let cells: Array = []; + const cells: Array = []; let prev = new Date(range.startTime); - let t = new Date(range.startTime); + const t = new Date(range.startTime); t.setMinutes(t.getMinutes() + size); for (; t.getTime() <= range.endTime; t.setMinutes(t.getMinutes() + size)) { cells.push({ startTime: prev.getTime(), endTime: t.getTime() }); From 4d27f2367d7424f65a9c005153f67aa25e1a3616 Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Fri, 28 Feb 2025 15:18:45 +0100 Subject: [PATCH 06/12] availibility merge vergessen --- src/lib/server/util/mergeAvailabilities.ts | 29 ++++++++++++++++++++ src/routes/taxi/availability/+page.server.ts | 10 +++++-- 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 src/lib/server/util/mergeAvailabilities.ts diff --git a/src/lib/server/util/mergeAvailabilities.ts b/src/lib/server/util/mergeAvailabilities.ts new file mode 100644 index 000000000..2d42557d9 --- /dev/null +++ b/src/lib/server/util/mergeAvailabilities.ts @@ -0,0 +1,29 @@ +import type { UnixtimeMs } from "$lib/util/UnixtimeMs"; +import type { VehicleId } from "../booking/VehicleId"; +import { groupBy } from "./groupBy"; +import { Interval } from "./interval"; + +//TODO schauen, wie ich das anpassen kann damit es für nils und mich passend/einfach ist +type valueType = { + Intervals: Interval[], + company: number +} + +export function mergeAvailabilities(availabilities: { + vehicleId: VehicleId, + startTime: UnixtimeMs, + endTime: UnixtimeMs, + company: number | undefined +}[]): Map { + // group availabilities by vehicle + const availabilitiesPerVehicle = groupBy( + availabilities, + (a) => a.vehicleId, + (a) => new Interval(a.startTime, a.endTime) + ); + // merge availabilities belonging to same vehicle + availabilitiesPerVehicle.forEach((availabilities, vehicle) => + availabilitiesPerVehicle.set(vehicle, Interval.merge(availabilities)) + ); + return availabilitiesPerVehicle; +} \ No newline at end of file diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index eb853ac40..93cd08d52 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -8,6 +8,7 @@ import { readInt } from '$lib/server/util/readForm'; import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; import type { Range } from './Range'; import { split } from './Range'; +import { mergeAvailabilities } from '$lib/server/util/mergeAvailabilities'; export async function load(event) { const companyId = event.locals.session?.companyId; @@ -66,9 +67,11 @@ export async function load(event) { .where('startTime', '<', toTime.getTime()) .where('endTime', '>', fromTime.getTime()) .where('company', '!=', companyId) - .select(['availability.id', 'startTime', 'endTime', 'vehicle', 'vehicle.company']) + .select(['startTime', 'endTime', 'vehicle', 'vehicle.company']) .execute(); + // TODO: availabilities müssen gemerged werden! + type heatinfo = { cell: Range; heat: number; @@ -90,7 +93,10 @@ export async function load(event) { for (const onecell of cell) { for (const heat of heatmapInfos) { if (isAInsideB(onecell, heat.startTime, heat.endTime)) { - heatcount++; // hier dann später Berechnung für gewichtete Summe einbauen + heatcount++; // hier dann später Berechnung für gewichtete Summe einbauen. + // TODO: + // - euklidische distanz für die distanz der Taxiunternehmen zueinander + // - gewichtung anhand der distanz in die heatmap einbauen } } heatarray.push({ cell: onecell, heat: heatcount }); From eb96455e2c38a519ad2ebee0f72acd900cb74810 Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Fri, 28 Feb 2025 15:29:14 +0100 Subject: [PATCH 07/12] wip --- src/lib/server/util/mergeAvailabilities.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/server/util/mergeAvailabilities.ts b/src/lib/server/util/mergeAvailabilities.ts index 2d42557d9..23dae20e3 100644 --- a/src/lib/server/util/mergeAvailabilities.ts +++ b/src/lib/server/util/mergeAvailabilities.ts @@ -6,14 +6,14 @@ import { Interval } from "./interval"; //TODO schauen, wie ich das anpassen kann damit es für nils und mich passend/einfach ist type valueType = { Intervals: Interval[], - company: number + company: number | undefined } export function mergeAvailabilities(availabilities: { vehicleId: VehicleId, + company: number | undefined, startTime: UnixtimeMs, endTime: UnixtimeMs, - company: number | undefined }[]): Map { // group availabilities by vehicle const availabilitiesPerVehicle = groupBy( From 4e5d29a49475de397426416326e5d5869ad009e6 Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Tue, 11 Mar 2025 12:45:11 +0100 Subject: [PATCH 08/12] minimal heatmap --- src/lib/server/util/mergeAvailabilities.ts | 29 ------------ src/routes/taxi/availability/+page.server.ts | 46 ++++++++++++++------ 2 files changed, 33 insertions(+), 42 deletions(-) delete mode 100644 src/lib/server/util/mergeAvailabilities.ts diff --git a/src/lib/server/util/mergeAvailabilities.ts b/src/lib/server/util/mergeAvailabilities.ts deleted file mode 100644 index 23dae20e3..000000000 --- a/src/lib/server/util/mergeAvailabilities.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { UnixtimeMs } from "$lib/util/UnixtimeMs"; -import type { VehicleId } from "../booking/VehicleId"; -import { groupBy } from "./groupBy"; -import { Interval } from "./interval"; - -//TODO schauen, wie ich das anpassen kann damit es für nils und mich passend/einfach ist -type valueType = { - Intervals: Interval[], - company: number | undefined -} - -export function mergeAvailabilities(availabilities: { - vehicleId: VehicleId, - company: number | undefined, - startTime: UnixtimeMs, - endTime: UnixtimeMs, -}[]): Map { - // group availabilities by vehicle - const availabilitiesPerVehicle = groupBy( - availabilities, - (a) => a.vehicleId, - (a) => new Interval(a.startTime, a.endTime) - ); - // merge availabilities belonging to same vehicle - availabilitiesPerVehicle.forEach((availabilities, vehicle) => - availabilitiesPerVehicle.set(vehicle, Interval.merge(availabilities)) - ); - return availabilitiesPerVehicle; -} \ No newline at end of file diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 93cd08d52..023155e50 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -8,7 +8,8 @@ import { readInt } from '$lib/server/util/readForm'; import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; import type { Range } from './Range'; import { split } from './Range'; -import { mergeAvailabilities } from '$lib/server/util/mergeAvailabilities'; +import { groupBy } from '$lib/server/util/groupBy'; +import { Interval } from '$lib/server/util/interval'; export async function load(event) { const companyId = event.locals.session?.companyId; @@ -62,15 +63,35 @@ export async function load(event) { // HEATMAP const heatmapInfos = await db + .with('thiszone', (db) => db + .selectFrom('company') + .where('id', '=', companyId) + .select(['zone'])) .selectFrom('availability') .innerJoin('vehicle', 'vehicle.id', 'availability.vehicle') - .where('startTime', '<', toTime.getTime()) - .where('endTime', '>', fromTime.getTime()) - .where('company', '!=', companyId) - .select(['startTime', 'endTime', 'vehicle', 'vehicle.company']) + .innerJoin('company', 'company.id', 'vehicle.company') + .innerJoin('thiszone', (join) => join.onTrue()) + .where('availability.startTime', '<', toTime.getTime()) + .where('availability.endTime', '>', fromTime.getTime()) + .where('vehicle.company', '!=', companyId) + .whereRef('thiszone.zone' as any, '=', 'company.zone') + .select(['availability.startTime', 'availability.endTime', 'availability.vehicle', 'vehicle.company']) .execute(); - // TODO: availabilities müssen gemerged werden! + const mergedheatinfos = groupBy( + heatmapInfos, + (a) => a.vehicle, + (a) => new Interval(a.startTime, a.endTime) + ); + mergedheatinfos.forEach((heatmap, vehicle) => + mergedheatinfos.set(vehicle, Interval.merge(heatmap)) + ); + const companybyVehicle = groupBy( + heatmapInfos, + (a) => a.vehicle, + (a) => a.company + ); + type heatinfo = { cell: Range; @@ -91,14 +112,13 @@ export async function load(event) { for (const hour of hours) { const cell = split(hour, 15); for (const onecell of cell) { - for (const heat of heatmapInfos) { - if (isAInsideB(onecell, heat.startTime, heat.endTime)) { - heatcount++; // hier dann später Berechnung für gewichtete Summe einbauen. - // TODO: - // - euklidische distanz für die distanz der Taxiunternehmen zueinander - // - gewichtung anhand der distanz in die heatmap einbauen + mergedheatinfos.forEach((heatIntervals) => { + for (const interval of heatIntervals) { + if (isAInsideB(onecell, interval.startTime, interval.endTime)) { + heatcount++; + } } - } + }) heatarray.push({ cell: onecell, heat: heatcount }); heatcount = 0; } From 89c21ab162565faa628278a9af554ce6f912570c Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Tue, 11 Mar 2025 13:09:08 +0100 Subject: [PATCH 09/12] changes due to format --- src/routes/taxi/availability/+page.server.ts | 24 ++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 023155e50..838fc4843 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -63,10 +63,7 @@ export async function load(event) { // HEATMAP const heatmapInfos = await db - .with('thiszone', (db) => db - .selectFrom('company') - .where('id', '=', companyId) - .select(['zone'])) + .with('thiszone', (db) => db.selectFrom('company').where('id', '=', companyId).select(['zone'])) .selectFrom('availability') .innerJoin('vehicle', 'vehicle.id', 'availability.vehicle') .innerJoin('company', 'company.id', 'vehicle.company') @@ -74,8 +71,13 @@ export async function load(event) { .where('availability.startTime', '<', toTime.getTime()) .where('availability.endTime', '>', fromTime.getTime()) .where('vehicle.company', '!=', companyId) - .whereRef('thiszone.zone' as any, '=', 'company.zone') - .select(['availability.startTime', 'availability.endTime', 'availability.vehicle', 'vehicle.company']) + .whereRef('thiszone.zone', '=', 'company.zone') + .select([ + 'availability.startTime', + 'availability.endTime', + 'availability.vehicle', + 'vehicle.company' + ]) .execute(); const mergedheatinfos = groupBy( @@ -83,15 +85,9 @@ export async function load(event) { (a) => a.vehicle, (a) => new Interval(a.startTime, a.endTime) ); - mergedheatinfos.forEach((heatmap, vehicle) => + mergedheatinfos.forEach((heatmap, vehicle) => mergedheatinfos.set(vehicle, Interval.merge(heatmap)) ); - const companybyVehicle = groupBy( - heatmapInfos, - (a) => a.vehicle, - (a) => a.company - ); - type heatinfo = { cell: Range; @@ -118,7 +114,7 @@ export async function load(event) { heatcount++; } } - }) + }); heatarray.push({ cell: onecell, heat: heatcount }); heatcount = 0; } From b40be5e6b2560b12304e012dc0eab0cdb8a897c3 Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Tue, 11 Mar 2025 13:36:20 +0100 Subject: [PATCH 10/12] file groupby in different location --- src/lib/{server => }/util/groupBy.ts | 0 src/routes/taxi/availability/+page.server.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/lib/{server => }/util/groupBy.ts (100%) diff --git a/src/lib/server/util/groupBy.ts b/src/lib/util/groupBy.ts similarity index 100% rename from src/lib/server/util/groupBy.ts rename to src/lib/util/groupBy.ts diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 838fc4843..50fb26f8d 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -8,7 +8,7 @@ import { readInt } from '$lib/server/util/readForm'; import type { UnixtimeMs } from '$lib/util/UnixtimeMs'; import type { Range } from './Range'; import { split } from './Range'; -import { groupBy } from '$lib/server/util/groupBy'; +import { groupBy } from '$lib/util/groupBy'; import { Interval } from '$lib/server/util/interval'; export async function load(event) { From 0b52caece37f82dc5e1df7e2a99b80d846bdc000 Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Tue, 11 Mar 2025 14:02:48 +0100 Subject: [PATCH 11/12] better sql query --- src/routes/taxi/availability/+page.server.ts | 31 ++++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 50fb26f8d..8afc9089e 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -63,22 +63,21 @@ export async function load(event) { // HEATMAP const heatmapInfos = await db - .with('thiszone', (db) => db.selectFrom('company').where('id', '=', companyId).select(['zone'])) - .selectFrom('availability') - .innerJoin('vehicle', 'vehicle.id', 'availability.vehicle') - .innerJoin('company', 'company.id', 'vehicle.company') - .innerJoin('thiszone', (join) => join.onTrue()) - .where('availability.startTime', '<', toTime.getTime()) - .where('availability.endTime', '>', fromTime.getTime()) - .where('vehicle.company', '!=', companyId) - .whereRef('thiszone.zone', '=', 'company.zone') - .select([ - 'availability.startTime', - 'availability.endTime', - 'availability.vehicle', - 'vehicle.company' - ]) - .execute(); + .selectFrom('company as company1') + .innerJoin('company as company2', 'company1.zone', 'company2.zone') + .innerJoin('vehicle', 'company2.id', 'vehicle.company') + .innerJoin('availability', 'vehicle.id', 'availability.vehicle') + .where('availability.startTime', '<', toTime.getTime()) + .where('availability.endTime', '>', fromTime.getTime()) + .where('company1.id', '=', companyId) + .where('company2.id', '!=', companyId) + .select([ + 'availability.startTime', + 'availability.endTime', + 'availability.vehicle', + 'vehicle.company' + ]) + .execute(); const mergedheatinfos = groupBy( heatmapInfos, From 3e3ecb7a62acf882f74f4ac8dfe0366242cf74f3 Mon Sep 17 00:00:00 2001 From: CmdrTMir Date: Tue, 11 Mar 2025 14:06:30 +0100 Subject: [PATCH 12/12] changes due to format --- src/routes/taxi/availability/+page.server.ts | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/routes/taxi/availability/+page.server.ts b/src/routes/taxi/availability/+page.server.ts index 8afc9089e..517bd1ec8 100644 --- a/src/routes/taxi/availability/+page.server.ts +++ b/src/routes/taxi/availability/+page.server.ts @@ -63,21 +63,21 @@ export async function load(event) { // HEATMAP const heatmapInfos = await db - .selectFrom('company as company1') - .innerJoin('company as company2', 'company1.zone', 'company2.zone') - .innerJoin('vehicle', 'company2.id', 'vehicle.company') - .innerJoin('availability', 'vehicle.id', 'availability.vehicle') - .where('availability.startTime', '<', toTime.getTime()) - .where('availability.endTime', '>', fromTime.getTime()) - .where('company1.id', '=', companyId) - .where('company2.id', '!=', companyId) - .select([ - 'availability.startTime', - 'availability.endTime', - 'availability.vehicle', - 'vehicle.company' - ]) - .execute(); + .selectFrom('company as company1') + .innerJoin('company as company2', 'company1.zone', 'company2.zone') + .innerJoin('vehicle', 'company2.id', 'vehicle.company') + .innerJoin('availability', 'vehicle.id', 'availability.vehicle') + .where('availability.startTime', '<', toTime.getTime()) + .where('availability.endTime', '>', fromTime.getTime()) + .where('company1.id', '=', companyId) + .where('company2.id', '!=', companyId) + .select([ + 'availability.startTime', + 'availability.endTime', + 'availability.vehicle', + 'vehicle.company' + ]) + .execute(); const mergedheatinfos = groupBy( heatmapInfos,