mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 23:53:25 +00:00
finished embedding
This commit is contained in:
@@ -14,7 +14,9 @@
|
||||
import { PUBLIC_MAPBOX_TOKEN } from '$env/static/public';
|
||||
|
||||
export let accessToken = PUBLIC_MAPBOX_TOKEN;
|
||||
export let geolocate = true;
|
||||
export let geocoder = true;
|
||||
export let hash = true;
|
||||
|
||||
mapboxgl.accessToken = accessToken;
|
||||
|
||||
@@ -35,7 +37,7 @@
|
||||
container: 'map',
|
||||
style: { version: 8, sources: {}, layers: [] },
|
||||
projection: { name: 'mercator' },
|
||||
hash: true,
|
||||
hash: hash,
|
||||
language: get(locale),
|
||||
attributionControl: false,
|
||||
logoPosition: 'bottom-right',
|
||||
@@ -66,16 +68,18 @@
|
||||
);
|
||||
}
|
||||
|
||||
newMap.addControl(
|
||||
new mapboxgl.GeolocateControl({
|
||||
positionOptions: {
|
||||
enableHighAccuracy: true
|
||||
},
|
||||
fitBoundsOptions,
|
||||
trackUserLocation: true,
|
||||
showUserHeading: true
|
||||
})
|
||||
);
|
||||
if (geolocate) {
|
||||
newMap.addControl(
|
||||
new mapboxgl.GeolocateControl({
|
||||
positionOptions: {
|
||||
enableHighAccuracy: true
|
||||
},
|
||||
fitBoundsOptions,
|
||||
trackUserLocation: true,
|
||||
showUserHeading: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
newMap.addControl(scaleControl);
|
||||
|
||||
|
@@ -74,6 +74,11 @@
|
||||
@apply hover:underline;
|
||||
}
|
||||
|
||||
:global(.markdown li > a) {
|
||||
@apply text-blue-500;
|
||||
@apply hover:underline;
|
||||
}
|
||||
|
||||
:global(.markdown kbd) {
|
||||
@apply p-1;
|
||||
@apply rounded-md;
|
||||
|
@@ -9,3 +9,10 @@
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
div :global(a) {
|
||||
@apply text-blue-500;
|
||||
@apply hover:underline;
|
||||
}
|
||||
</style>
|
||||
|
@@ -18,14 +18,25 @@
|
||||
|
||||
$embedding = true;
|
||||
|
||||
const { currentBasemap, distanceUnits, velocityUnits, temperatureUnits, fileOrder } = settings;
|
||||
const {
|
||||
currentBasemap,
|
||||
distanceUnits,
|
||||
velocityUnits,
|
||||
temperatureUnits,
|
||||
fileOrder,
|
||||
distanceMarkers,
|
||||
directionMarkers
|
||||
} = settings;
|
||||
|
||||
export let options: EmbeddingOptions;
|
||||
export let hash: string;
|
||||
|
||||
let prevUnits = {
|
||||
distance: '',
|
||||
velocity: '',
|
||||
temperature: ''
|
||||
let prevSettings = {
|
||||
distanceMarkers: false,
|
||||
directionMarkers: false,
|
||||
distanceUnits: 'metric',
|
||||
velocityUnits: 'speed',
|
||||
temperatureUnits: 'celsius'
|
||||
};
|
||||
|
||||
function applyOptions() {
|
||||
@@ -97,29 +108,39 @@
|
||||
return $selection;
|
||||
});
|
||||
|
||||
map.subscribe(($map) => {
|
||||
if ($map) {
|
||||
$map.fitBounds(
|
||||
[
|
||||
bounds.southWest.lon,
|
||||
bounds.southWest.lat,
|
||||
bounds.northEast.lon,
|
||||
bounds.northEast.lat
|
||||
],
|
||||
{
|
||||
padding: 80,
|
||||
linear: true,
|
||||
easing: () => 1
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
if (hash.length === 0) {
|
||||
map.subscribe(($map) => {
|
||||
if ($map) {
|
||||
$map.fitBounds(
|
||||
[
|
||||
bounds.southWest.lon,
|
||||
bounds.southWest.lat,
|
||||
bounds.northEast.lon,
|
||||
bounds.northEast.lat
|
||||
],
|
||||
{
|
||||
padding: 80,
|
||||
linear: true,
|
||||
easing: () => 1
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (options.basemap !== $currentBasemap && allowedEmbeddingBasemaps.includes(options.basemap)) {
|
||||
$currentBasemap = options.basemap;
|
||||
}
|
||||
|
||||
if (options.distanceMarkers !== $distanceMarkers) {
|
||||
$distanceMarkers = options.distanceMarkers;
|
||||
}
|
||||
|
||||
if (options.directionMarkers !== $directionMarkers) {
|
||||
$directionMarkers = options.directionMarkers;
|
||||
}
|
||||
|
||||
if (options.distanceUnits !== $distanceUnits) {
|
||||
$distanceUnits = options.distanceUnits;
|
||||
}
|
||||
@@ -134,9 +155,11 @@
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
prevUnits.distance = $distanceUnits;
|
||||
prevUnits.velocity = $velocityUnits;
|
||||
prevUnits.temperature = $temperatureUnits;
|
||||
prevSettings.distanceMarkers = $distanceMarkers;
|
||||
prevSettings.directionMarkers = $directionMarkers;
|
||||
prevSettings.distanceUnits = $distanceUnits;
|
||||
prevSettings.velocityUnits = $velocityUnits;
|
||||
prevSettings.temperatureUnits = $temperatureUnits;
|
||||
});
|
||||
|
||||
$: if (options) {
|
||||
@@ -144,16 +167,24 @@
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if ($distanceUnits !== prevUnits.distance) {
|
||||
$distanceUnits = prevUnits.distance;
|
||||
if ($distanceMarkers !== prevSettings.distanceMarkers) {
|
||||
$distanceMarkers = prevSettings.distanceMarkers;
|
||||
}
|
||||
|
||||
if ($velocityUnits !== prevUnits.velocity) {
|
||||
$velocityUnits = prevUnits.velocity;
|
||||
if ($directionMarkers !== prevSettings.directionMarkers) {
|
||||
$directionMarkers = prevSettings.directionMarkers;
|
||||
}
|
||||
|
||||
if ($temperatureUnits !== prevUnits.temperature) {
|
||||
$temperatureUnits = prevUnits.temperature;
|
||||
if ($distanceUnits !== prevSettings.distanceUnits) {
|
||||
$distanceUnits = prevSettings.distanceUnits;
|
||||
}
|
||||
|
||||
if ($velocityUnits !== prevSettings.velocityUnits) {
|
||||
$velocityUnits = prevSettings.velocityUnits;
|
||||
}
|
||||
|
||||
if ($temperatureUnits !== prevSettings.temperatureUnits) {
|
||||
$temperatureUnits = prevSettings.temperatureUnits;
|
||||
}
|
||||
|
||||
$fileOrder = $fileOrder.filter((id) => !id.includes('embed'));
|
||||
@@ -166,6 +197,8 @@
|
||||
class="h-full {$fileObservers.size > 1 ? 'horizontal' : ''}"
|
||||
accessToken={options.token}
|
||||
geocoder={false}
|
||||
geolocate={false}
|
||||
hash={false}
|
||||
/>
|
||||
<OpenIn bind:files={options.files} />
|
||||
<LayerControl />
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { basemaps } from "$lib/assets/layers";
|
||||
|
||||
export type EmbeddingOptions = {
|
||||
token: string;
|
||||
files: string[];
|
||||
@@ -13,6 +15,8 @@ export type EmbeddingOptions = {
|
||||
temp: boolean,
|
||||
power: boolean,
|
||||
},
|
||||
distanceMarkers: boolean,
|
||||
directionMarkers: boolean,
|
||||
distanceUnits: 'metric' | 'imperial',
|
||||
velocityUnits: 'speed' | 'pace',
|
||||
temperatureUnits: 'celsius' | 'fahrenheit',
|
||||
@@ -33,6 +37,8 @@ export const defaultEmbeddingOptions = {
|
||||
temp: false,
|
||||
power: false,
|
||||
},
|
||||
distanceMarkers: false,
|
||||
directionMarkers: false,
|
||||
distanceUnits: 'metric',
|
||||
velocityUnits: 'speed',
|
||||
temperatureUnits: 'celsius',
|
||||
@@ -57,7 +63,4 @@ export function getCleanedEmbeddingOptions(options: any, defaultOptions: any = d
|
||||
return cleanedOptions;
|
||||
}
|
||||
|
||||
export const allowedEmbeddingBasemaps = [
|
||||
'mapboxOutdoors',
|
||||
'mapboxSatellite',
|
||||
];
|
||||
export const allowedEmbeddingBasemaps = Object.keys(basemaps).filter(basemap => !['ordnanceSurvey'].includes(basemap));
|
@@ -5,7 +5,16 @@
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||
import * as RadioGroup from '$lib/components/ui/radio-group';
|
||||
import { Zap, HeartPulse, Orbit, Thermometer, SquareActivity } from 'lucide-svelte';
|
||||
import {
|
||||
Zap,
|
||||
HeartPulse,
|
||||
Orbit,
|
||||
Thermometer,
|
||||
SquareActivity,
|
||||
Coins,
|
||||
Milestone,
|
||||
Video
|
||||
} from 'lucide-svelte';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import {
|
||||
allowedEmbeddingBasemaps,
|
||||
@@ -35,11 +44,11 @@
|
||||
|
||||
let manualCamera = false;
|
||||
|
||||
let zoom = 0;
|
||||
let lat = 0;
|
||||
let lon = 0;
|
||||
let bearing = 0;
|
||||
let pitch = 0;
|
||||
let zoom = '0';
|
||||
let lat = '0';
|
||||
let lon = '0';
|
||||
let bearing = '0';
|
||||
let pitch = '0';
|
||||
|
||||
$: hash = manualCamera ? `#${zoom}/${lat}/${lon}/${bearing}/${pitch}` : '';
|
||||
|
||||
@@ -58,6 +67,21 @@
|
||||
$: if (options.elevation.height || options.elevation.show) {
|
||||
resizeMap();
|
||||
}
|
||||
|
||||
function updateCamera() {
|
||||
if ($map) {
|
||||
let center = $map.getCenter();
|
||||
lat = center.lat.toFixed(4);
|
||||
lon = center.lng.toFixed(4);
|
||||
zoom = $map.getZoom().toFixed(2);
|
||||
bearing = $map.getBearing().toFixed(1);
|
||||
pitch = $map.getPitch().toFixed(0);
|
||||
}
|
||||
}
|
||||
|
||||
$: if ($map) {
|
||||
$map.on('moveend', updateCamera);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card.Root>
|
||||
@@ -164,6 +188,20 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Checkbox id="distance-markers" bind:checked={options.distanceMarkers} />
|
||||
<Label for="distance-markers" class="flex flex-row items-center gap-1">
|
||||
<Coins size="16" />
|
||||
{$_('menu.distance_markers')}
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Checkbox id="direction-markers" bind:checked={options.directionMarkers} />
|
||||
<Label for="direction-markers" class="flex flex-row items-center gap-1">
|
||||
<Milestone size="16" />
|
||||
{$_('menu.direction_markers')}
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-row flex-wrap justify-between gap-3">
|
||||
<Label class="flex flex-col items-start gap-2">
|
||||
{$_('menu.distance_units')}
|
||||
@@ -205,18 +243,52 @@
|
||||
</RadioGroup.Root>
|
||||
</Label>
|
||||
</div>
|
||||
<div class="flex flex-col gap-3 p-3 border rounded-md">
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
<Checkbox id="manual-camera" bind:checked={manualCamera} />
|
||||
<Label for="manual-camera" class="flex flex-row items-center gap-1">
|
||||
<Video size="16" />
|
||||
{$_('embedding.manual_camera')}
|
||||
</Label>
|
||||
</div>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{$_('embedding.manual_camera_description')}
|
||||
</p>
|
||||
<div class="flex flex-row flex-wrap items-center gap-6">
|
||||
<Label class="flex flex-col gap-1">
|
||||
<span>{$_('embedding.latitude')}</span>
|
||||
<span>{lat}</span>
|
||||
</Label>
|
||||
<Label class="flex flex-col gap-1">
|
||||
<span>{$_('embedding.longitude')}</span>
|
||||
<span>{lon}</span>
|
||||
</Label>
|
||||
<Label class="flex flex-col gap-1">
|
||||
<span>{$_('embedding.zoom')}</span>
|
||||
<span>{zoom}</span>
|
||||
</Label>
|
||||
<Label class="flex flex-col gap-1">
|
||||
<span>{$_('embedding.bearing')}</span>
|
||||
<span>{bearing}</span>
|
||||
</Label>
|
||||
<Label class="flex flex-col gap-1">
|
||||
<span>{$_('embedding.pitch')}</span>
|
||||
<span>{pitch}</span>
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
<Label>
|
||||
{$_('embedding.preview')}
|
||||
</Label>
|
||||
<div class="relative h-[600px]">
|
||||
<Embedding bind:options={iframeOptions} />
|
||||
<Embedding bind:options={iframeOptions} bind:hash />
|
||||
</div>
|
||||
<Label>
|
||||
{$_('embedding.code')}
|
||||
</Label>
|
||||
<pre class="bg-primary text-primary-foreground p-3 rounded-md whitespace-normal break-all">
|
||||
<code class="language-html">
|
||||
{`<iframe src="https://gpx.studio${base}/embed?options=${encodeURIComponent(JSON.stringify(getCleanedEmbeddingOptions(options)))}${hash}" width="100%" height="600px" frameborder="0" />`}
|
||||
{`<iframe src="https://gpx.studio${base}/embed?options=${encodeURIComponent(JSON.stringify(getCleanedEmbeddingOptions(options)))}${hash}" width="100%" height="600px" frameborder="0" style="outline: none;"/>`}
|
||||
</code>
|
||||
</pre>
|
||||
</fieldset>
|
||||
|
@@ -10,7 +10,7 @@
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="absolute top-0 flex-wrap h-fit bg-background font-semibold rounded-md py-1 px-2 gap-1.5 xs:text-base mt-2.5 ml-2.5 mr-12"
|
||||
href="{getURLForLanguage($locale, '/embed')}?files={encodeURIComponent(JSON.stringify(files))}"
|
||||
href="{getURLForLanguage($locale, '/app')}?files={encodeURIComponent(JSON.stringify(files))}"
|
||||
target="_blank"
|
||||
>
|
||||
{$_('menu.open_in')}
|
||||
|
@@ -9,8 +9,16 @@ title: Integration
|
||||
|
||||
# { title }
|
||||
|
||||
<DocsNote>
|
||||
This section is a work in progress.
|
||||
You can use **gpx.studio** to create maps showing your GPX files and embed them in your website.
|
||||
|
||||
All you need is:
|
||||
1. A <a href="https://account.mapbox.com/auth/signup" target="_blank">Mapbox access token</a> to load the map, and
|
||||
1. GPX files hosted on your server or a public URL.
|
||||
|
||||
You can then play with the configurator below to customize your map and generate the corresponding HTML code.
|
||||
|
||||
<DocsNote type="warning">
|
||||
You will need to set up <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" target="_blank">Cross-Origin Resource Sharing (CORS)</a> headers on your server to allow <b>gpx.studio</b> to load your GPX files.
|
||||
</DocsNote>
|
||||
|
||||
<EmbeddingPlaygound />
|
||||
|
@@ -25,7 +25,7 @@ You can use the search bar to look for an address and navigate to it on the map.
|
||||
The locate button will center the map on your current location.
|
||||
|
||||
<DocsNote>
|
||||
This only works if you have allowed your browser and the website to access your location.
|
||||
This only works if you have allowed your browser and <b>gpx.studio</b> to access your location.
|
||||
</DocsNote>
|
||||
|
||||
### <PersonStanding size="16" class="inline-block" style="margin-bottom: 2px" /> Street view
|
||||
|
@@ -44,5 +44,5 @@ Open the export dialog to save the currently selected files to your computer.
|
||||
Open the export dialog to save all files to your computer.
|
||||
|
||||
<DocsNote type="warning">
|
||||
If your download does not start after clicking the download button, please check your browser settings to allow downloads from this website.
|
||||
If your download does not start after clicking the download button, please check your browser settings to allow downloads from <b>gpx.studio</b>.
|
||||
</DocsNote>
|
@@ -20,5 +20,5 @@ Applying the tool to a file containing multiple tracks will create a new file fo
|
||||
Similarly, applying the tool to a track containing multiple segments will create (in the same file) a new track for each of the segments it contains.
|
||||
|
||||
<DocsNote>
|
||||
When extracting the tracks of a file containing [points of interest](../gpx), the tool will automatically assign each point of interest to the track it is closest to.
|
||||
When extracting the tracks of a file containing <a href="../gpx">points of interest</a>, the tool will automatically assign each point of interest to the track it is closest to.
|
||||
</DocsNote>
|
@@ -382,9 +382,9 @@
|
||||
"show_controls": "Show controls",
|
||||
"manual_camera": "Manual camera",
|
||||
"manual_camera_description": "You can move the map below to adjust the camera position.",
|
||||
"zoom": "Zoom",
|
||||
"latitude": "Latitude",
|
||||
"longitude": "Longitude",
|
||||
"zoom": "Zoom",
|
||||
"pitch": "Pitch",
|
||||
"bearing": "Bearing",
|
||||
"preview": "Preview",
|
||||
|
@@ -23,5 +23,5 @@
|
||||
</script>
|
||||
|
||||
{#if embeddingOptions}
|
||||
<Embedding options={embeddingOptions} />
|
||||
<Embedding options={embeddingOptions} hash={$page.url.hash} />
|
||||
{/if}
|
||||
|
Reference in New Issue
Block a user