-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature values can be selected and will be displayed as petals. The petal colors can be selected individually.
- Loading branch information
Showing
13 changed files
with
475 additions
and
32 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
<script lang="ts" setup> | ||
import { ChevronDown } from "lucide-vue-next"; | ||
import { useColorsStore } from "@/stores/use-colors-store"; | ||
import { useGeojsonStore } from "@/stores/use-geojson-store.ts"; | ||
import type { GeojsonMapSchema } from "@/types/global.d"; | ||
interface Props { | ||
params: Zod.infer<typeof GeojsonMapSchema>["params"]; | ||
} | ||
const props = defineProps<Props>(); | ||
const { params } = toRefs(props); | ||
const GeojsonStore = useGeojsonStore(); | ||
const { tables } = storeToRefs(GeojsonStore); | ||
const table = computed(() => tables.value.get(params.value.url)); | ||
const categories = computed(() => { | ||
return table.value?.getAllColumns().filter((column) => column.getCanHide()); | ||
}); | ||
function titleCase(s: string) { | ||
return s | ||
.replace(/^[-_]*(.)/, (_, c) => c.toUpperCase()) // Initial char (after -/_) | ||
.replace(/[-_]+(.)/g, (_, c) => " " + c.toUpperCase()); // First char after each -/_ | ||
} | ||
const isCollapsibleOpen = ref(categories.value!.map(() => false)); | ||
const { colors, addColor, setColor } = useColorsStore(); | ||
</script> | ||
|
||
<template> | ||
<div class="grid items-center border-b border-border bg-surface px-8 py-3 text-on-surface"> | ||
<div class="flex flex-wrap items-center gap-x-4 gap-y-1 text-sm font-medium text-on-surface/75"> | ||
<div v-for="(group, idx) in categories" :key="group.id"> | ||
<DropdownMenu v-slot="{ open }" v-model:open="isCollapsibleOpen[idx]"> | ||
<DropdownMenuTrigger class="flex w-full items-center gap-1 p-2 text-sm"> | ||
<span>{{ titleCase(group.id) }}</span> | ||
<Badge | ||
v-if="group.getLeafColumns().filter((c) => c.getIsVisible()).length" | ||
variant="outline" | ||
>{{ group.getLeafColumns().filter((c) => c.getIsVisible()).length }}</Badge | ||
> | ||
|
||
<ChevronDown class="size-4" :class="open ? 'rotate-180' : ''"></ChevronDown> | ||
</DropdownMenuTrigger> | ||
|
||
<DropdownMenuContent class=""> | ||
<DropdownMenuCheckboxItem | ||
v-for="column in group.columns" | ||
:key="column.id" | ||
:checked="column.getIsVisible()" | ||
@select.prevent | ||
@update:checked=" | ||
(value) => { | ||
column.toggleVisibility(!!value); | ||
column.setFilterValue([]); | ||
if (!colors.has(column.id)) addColor(column.id); | ||
} | ||
" | ||
> | ||
<span class="flex-1">{{ column.columnDef.header }}</span> | ||
<label v-if="column.getIsVisible()" class="grow-0 basis-0 p-0"> | ||
<input | ||
class="size-5" | ||
type="color" | ||
:value="colors.get(column.id)?.colorCode || '#cccccc'" | ||
@click.capture.stop | ||
@input=" | ||
(event) => { | ||
//@ts-expect-error target.value not recognized | ||
setColor({ id: column.id, colorCode: event.target!.value }); | ||
} | ||
" | ||
/> | ||
<span class="sr-only">Select color</span> | ||
</label> | ||
</DropdownMenuCheckboxItem> | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
</div> | ||
</div> | ||
</div> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import type { Column } from "@tanstack/vue-table"; | ||
import type { Feature as GeoJsonFeature, Point } from "geojson"; | ||
import { divIcon, type LatLng, marker } from "leaflet"; | ||
|
||
import type { MarkerProperties } from "@/lib/api-client"; | ||
import { useGeojsonStore } from "@/stores/use-geojson-store.ts"; | ||
|
||
const GeojsonStore = useGeojsonStore(); | ||
const { tables } = storeToRefs(GeojsonStore); | ||
const url = "https://raw.githubusercontent.com/wibarab/wibarab-data/main/wibarab_varieties.geojson"; | ||
|
||
function getPetalSVG(entries: Array<Column<never>>) { | ||
const div = document.createElement("div"); | ||
div.className = "hover:scale-150 transition origin-center relative size-6"; | ||
const NUM_PETALS = entries.length; | ||
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | ||
svg.setAttribute("width", "12px"); | ||
svg.setAttribute("height", "12px"); | ||
svg.classList.add("overflow-visible"); | ||
// svg.setHTMLUnsafe(String(petal)); | ||
for (const [i, value] of entries.entries()) { | ||
const petal = document.createElementNS("http://www.w3.org/2000/svg", "use"); | ||
petal.setAttribute("href", "#petal"); | ||
|
||
petal.style.fill = `var(--${value.id}, #cccccc)`; | ||
petal.style.transformOrigin = "bottom"; | ||
petal.style.transform = `rotate(${String((i * 360) / NUM_PETALS)}deg)`; | ||
petal.classList.add("size-3", "absolute", "ml-1.5"); | ||
petal.setAttribute("title", value.id); | ||
svg.appendChild(petal); | ||
} | ||
|
||
div.appendChild(svg); | ||
|
||
return div; | ||
} | ||
|
||
export function usePetalMarker(feature: GeoJsonFeature<Point, MarkerProperties>, latlng: LatLng) { | ||
const table = tables.value.get(url); | ||
const columns = table | ||
?.getVisibleLeafColumns() | ||
.filter( | ||
(col) => col.getCanFilter() && Object.keys(feature.properties).find((k) => k === col.id), | ||
); | ||
//@ts-expect-error missing accessorFn | ||
const htmlContent = getPetalSVG(columns).outerHTML; // Example HTML content | ||
const customIcon = divIcon({ | ||
html: htmlContent, | ||
className: "custom-marker-icon size-5", // Add custom CSS class for styling | ||
// iconSize: [30, 30], // Adjust size as needed | ||
}); | ||
|
||
const leafletMarker = marker(latlng, { | ||
icon: customIcon, | ||
}); | ||
return leafletMarker; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.