Skip to content

Commit 08e5e99

Browse files
authored
Merge pull request #45 from UW-Macrostrat/explore
Explore Filter
2 parents 2cd9f28 + de10373 commit 08e5e99

File tree

10 files changed

+376
-128
lines changed

10 files changed

+376
-128
lines changed

pages/+Page.client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export function Page() {
3737
])
3838
])
3939
]),
40-
h("div", { className: "new_container map-container" }, [
40+
h("div", { className: "new_container maps-container" }, [
4141
h("div", { className: "map-imgs" }, [
4242
h(Image, { src: "main-page/grand_canyon.jpg", className: "map-shot grand_canyon" }),
4343
h(Image, { src: "main-page/new_zealand.jpg", className: "map-shot new_zealand" }),

pages/explore/+Page.client.ts

Lines changed: 236 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ import styles from "../main.module.sass";
1919
import { createCheckins, useRockdAPI, Image } from "../index";
2020
import "./main.sass";
2121
import "@macrostrat/style-system";
22-
import { LngLatCoords } from "@macrostrat/map-interface";
23-
import { set } from "react-datepicker/dist/date_utils";
24-
import { configDefinitionsBuiltInGlobal } from "vike/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn";
25-
import chroma from "chroma-js";
22+
import { MapPosition } from "@macrostrat/mapbox-utils";
2623

2724
const h = hyper.styled(styles);
2825

@@ -145,6 +142,9 @@ function WeaverMap({
145142
const style = useMapStyle(type, mapboxToken, showSatelite, showOverlay);
146143
const [selectedCheckin, setSelectedCheckin] = useState(null);
147144
const [showSettings, setSettings] = useState(false);
145+
const [showFilter, setFilter] = useState(false);
146+
const [filteredCheckins, setFilteredCheckins] = useState(false);
147+
const [filteredData, setFilteredData] = useState(null);
148148

149149
// overlay
150150
const [inspectPosition, setInspectPosition] = useState<mapboxgl.LngLat | null>(null);
@@ -174,8 +174,11 @@ function WeaverMap({
174174
selectedCheckin ? `protected/checkins?checkin_id=${selectedCheckin}` : null
175175
);
176176

177-
const toolbar = h(Toolbar, {showSettings, setSettings});
177+
const toolbar = h(Toolbar, {showSettings, setSettings, showFilter, setFilter});
178178
const contextPanel = h(ContextPanel, {showSettings, showSatelite, setSatelite, showOverlay, setOverlay});
179+
const autoComplete = h(AutoComplete, {showFilter, setFilteredCheckins, setFilteredData});
180+
181+
const test = h(createFilteredCheckins, {filteredData, setInspectPosition});
179182

180183
if(selectedCheckin && checkinData) {
181184
const clickedCheckins = h(createSelectedCheckins, {data: checkinData?.success.data, setInspectPosition});
@@ -198,6 +201,16 @@ function WeaverMap({
198201
}, "X"),
199202
h("div.overlay-div", clickedCheckins),
200203
]);
204+
} else if (filteredCheckins) {
205+
overlay = h("div.sidebox", [
206+
h('div.sidebox-header', [
207+
h('div.title', [
208+
toolbar,
209+
h("h1", "Filtered Checkins"),
210+
]),
211+
]),
212+
h("div.overlay-div", test),
213+
]);
201214
} else {
202215
overlay = h("div.sidebox", [
203216
h('div.sidebox-header', [
@@ -212,14 +225,28 @@ function WeaverMap({
212225

213226
if(style == null) return null;
214227

228+
const sidePanel = h("div.side-panel", [
229+
autoComplete,
230+
contextPanel,
231+
])
232+
233+
234+
const mapPosition: MapPosition = {
235+
camera: {
236+
lat: 0,
237+
lng: 0,
238+
altitude: 30000000,
239+
},
240+
};
241+
215242
return h(
216243
"div.map-container",
217244
[
218245
// The Map Area Container
219246
h(
220247
MapAreaContainer,
221248
{
222-
contextPanel: contextPanel,
249+
contextPanel: sidePanel,
223250
className: "map-area-container",
224251
style: { "padding-left": "calc(30% + 14px)",},
225252
},
@@ -324,31 +351,40 @@ function FeatureDetails({setInspectPosition}) {
324351
]);
325352
}
326353

327-
function Toolbar({showSettings, setSettings}) {
354+
function Toolbar({showSettings, setSettings, showFilter, setFilter}) {
328355
return h("div", { className: "toolbar", style: {padding: "0"} }, [
329356
h("div.toolbar-header", [
330357
h("a", { href: "/" },
331358
h(Image, { className: "home-icon", src: "favicon-32x32.png" }),
332359
),
360+
h(Icon, { className: "settings-icon", icon: "filter", onClick: () => {
361+
setFilter(!showFilter);
362+
}
363+
}),
333364
h(Icon, { className: "settings-icon", icon: "settings", onClick: () => {
334-
setSettings(!showSettings);
335-
}
365+
setSettings(!showSettings);
366+
}
336367
}),
337368
]),
338369
]);
339370
}
340371

341372
function ContextPanel({showSettings, showSatelite, setSatelite, showOverlay, setOverlay}) {
342373
return h(PanelCard, { className: showSettings ? "settings-content" : "hide" }, [
374+
h("div", { className: "settings-header" }, [
375+
h(Icon, { className: "settings-icon", icon: "settings"}),
376+
h("h1", "Settings"),
377+
]),
378+
h(Divider, {className: "settings-divider"}),
343379
h("div", { className: "settings" }, [
344380
h(DarkModeButton, { className: "dark-btn", showText: true } ),
345-
h(PanelCard, {className: "satellite-style", onClick: () => {
381+
h(PanelCard, {className: showSatelite ? "selected satellite-style" : "satellite-style", onClick: () => {
346382
setSatelite(!showSatelite);
347383
}}, [
348384
h(Icon, { className: "satellite-icon", icon: "satellite"}),
349385
h("p", "Satellite"),
350386
]),
351-
h(PanelCard, {className: "map-style", onClick: () => {
387+
h(PanelCard, {className: showOverlay ? "selected map-style" : "map-style", onClick: () => {
352388
setOverlay(!showOverlay);
353389
}}, [
354390
h(Icon, { className: "overlay-icon", icon: "map"}),
@@ -359,22 +395,6 @@ function ContextPanel({showSettings, showSatelite, setSatelite, showOverlay, set
359395
])
360396
}
361397

362-
function handleClusterClick() {
363-
const mapRef = useMapRef();
364-
const map = mapRef.current;
365-
// handle cluster click
366-
map?.on('click', 'clusters', (e) => {
367-
console.log("cluster click");
368-
const features = map.queryRenderedFeatures(e.point, {
369-
layers: ['clusters']
370-
});
371-
372-
console.log("features", features[0].properties.expansion_zoom);
373-
});
374-
375-
return null;
376-
}
377-
378398
function ClickedCheckins({setSelectedCheckin}) {
379399
const mapRef = useMapRef();
380400
const map = mapRef.current;
@@ -439,4 +459,193 @@ function createSelectedCheckins(result, setInspectPosition) {
439459
const mapRef = useMapRef();
440460

441461
return createCheckins(result.data, mapRef, setInspectPosition);
462+
}
463+
464+
function createFilteredCheckins(filteredData, setInspectPosition) {
465+
const mapRef = useMapRef();
466+
467+
return createCheckins(filteredData?.filteredData, mapRef, setInspectPosition);
468+
}
469+
470+
function AutoComplete({showFilter, setFilteredCheckins, setFilteredData}) {
471+
const mapRef = useMapRef();
472+
const map = mapRef.current;
473+
const [filters, setFilters] = useState([]);
474+
const [autocompleteOpen, setAutocompleteOpen] = useState(true);
475+
const [input, setInput] = useState('');
476+
const [close, setClose] = useState(false);
477+
478+
const person_data = getPersonCheckins(filters.length > 0 ? filters[0].id : 0)?.success.data;
479+
480+
if(person_data && person_data.length > 0) {
481+
setFilteredCheckins(true);
482+
setFilteredData(person_data);
483+
} else {
484+
setFilteredCheckins(false);
485+
}
486+
487+
// add markers for filtered checkins
488+
let coordinates = [];
489+
let lngs = [];
490+
let lats = [];
491+
492+
if(person_data && person_data.length > 0) {
493+
person_data.forEach((checkin) => {
494+
coordinates.push([checkin.lng, checkin.lat]);
495+
lngs.push(checkin.lng);
496+
lats.push(checkin.lat);
497+
});
498+
499+
let previous = document.querySelectorAll('.filtered_pin');
500+
previous.forEach((marker) => {
501+
marker.remove();
502+
});
503+
504+
let previousFeatured = document.querySelectorAll('.marker_pin');
505+
previousFeatured.forEach((marker) => {
506+
marker.remove();
507+
});
508+
509+
if (!close) {
510+
let stop = 0;
511+
coordinates.forEach((coord) => {
512+
stop++;
513+
// marker
514+
const el = document.createElement('div');
515+
el.className = 'filtered_pin';
516+
517+
// Create marker
518+
new mapboxgl.Marker(el)
519+
.setLngLat(coord)
520+
.addTo(map);
521+
});
522+
}
523+
524+
map.fitBounds([
525+
[ Math.max(...lngs), Math.max(...lats) ],
526+
[ Math.min(...lngs), Math.min(...lats) ]
527+
], {
528+
maxZoom: 12,
529+
duration: 0,
530+
padding: 75
531+
});
532+
}
533+
534+
// rest
535+
const handleInputChange = (event) => {
536+
setAutocompleteOpen(true);
537+
setInput(event.target.value);
538+
setClose(false);
539+
};
540+
541+
let result = null;
542+
543+
try {
544+
result = useRockdAPI("autocomplete/" + input);
545+
} catch (e) {
546+
return null;
547+
}
548+
549+
let searchBar = h('div.search-bar', [
550+
h('input', { type: "text", placeholder: "Search name", onChange: handleInputChange }),
551+
h('div.x-icon', [
552+
h(Icon, { icon: "cross", onClick: () => {
553+
let input = document.querySelector('input');
554+
input.value = "";
555+
setAutocompleteOpen(false);
556+
setClose(true);
557+
setFilters([]);
558+
559+
let previous = document.querySelectorAll('.filtered_pin');
560+
previous.forEach((marker) => {
561+
marker.remove();
562+
});
563+
}
564+
}),
565+
]),
566+
]);
567+
568+
let filterContainer = filters.length != 0 ? h("div.filter-container", [
569+
h('h2', "Filters"),
570+
h('ul', filters.map((item) => {
571+
return h("div.filter-item", [
572+
h('li', item.name),
573+
h(Icon, { icon: "cross", style: {color: "red"}, onClick: () => {
574+
setFilters(filters.filter((filter) => filter != item));
575+
if(filters.length == 1) {
576+
setClose(true);
577+
578+
let previous = document.querySelectorAll('.filtered_pin');
579+
previous.forEach((marker) => {
580+
marker.remove();
581+
});
582+
}
583+
}
584+
})
585+
])
586+
})),
587+
]) : null;
588+
589+
if(!result || close) return h(PanelCard, {className: showFilter ? "autocomplete" : "hide"}, [
590+
h("div", { className: "search-header" }, [
591+
h(Icon, { className: "search-icon", icon: "filter"}),
592+
h("h1", "Filter Checkins"),
593+
]),
594+
h(Divider, {className: "filter-divider"}),
595+
searchBar
596+
]);
597+
result = result.success.data;
598+
599+
let taxa = result.taxa.length > 0 && autocompleteOpen ? h('div.taxa', [
600+
h('h2', "Taxa"),
601+
h('ul', result.taxa.map((item) => {
602+
return h('li', {
603+
onClick: () => {
604+
if(!filters.includes(item)) {
605+
setAutocompleteOpen(false);
606+
setFilters(filters.concat([item]));
607+
console.log(item.id)
608+
}
609+
}
610+
}, item.name);
611+
}))
612+
]) : null;
613+
614+
let people = result.people.length > 0 && autocompleteOpen ? h('div.people', [
615+
h('h2', "People"),
616+
h('ul', result.people.map((item) => {
617+
return h('li', {
618+
onClick: () => {
619+
if(!filters.includes(item)) {
620+
setAutocompleteOpen(false);
621+
setFilters(filters.concat([item]));
622+
}
623+
}
624+
}, item.name);
625+
}))
626+
]) : null;
627+
628+
const results = h("div.results", [
629+
taxa,
630+
people,
631+
]);
632+
633+
const wrapper = h('div.autocomplete-wrapper', [
634+
filterContainer,
635+
results,
636+
]);
637+
638+
return h(PanelCard, {className: showFilter ? "autocomplete" : "hide"}, [
639+
h("div", { className: "search-header" }, [
640+
h(Icon, { className: "search-icon", icon: "filter"}),
641+
h("h1", "Filter Checkins"),
642+
]),
643+
h(Divider, {className: "filter-divider"}),
644+
searchBar,
645+
wrapper
646+
]);
647+
}
648+
649+
function getPersonCheckins(personId) {
650+
return useRockdAPI("protected/checkins?person_id=" + personId);
442651
}

0 commit comments

Comments
 (0)