0
0
mirror of https://github.com/PostHog/posthog.git synced 2024-11-21 13:39:22 +01:00

feat(hackathon-3000): use protomap tiles from s3 (#18247)

This commit is contained in:
Thomas Obermüller 2023-10-30 14:14:12 +01:00 committed by GitHub
parent 1744d127ed
commit ba570e19e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 86 additions and 46 deletions

View File

@ -1 +0,0 @@
MAPLIBRE_STYLE_URL=https://api.example.com/style.json?key=mykey

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -6,7 +6,6 @@ declare global {
JS_POSTHOG_API_KEY?: string
JS_POSTHOG_HOST?: string
JS_POSTHOG_SELF_CAPTURE?: boolean
JS_MAPLIBRE_STYLE_URL?: string
JS_CAPTURE_TIME_TO_SEE_DATA?: boolean
JS_KEA_VERBOSE_LOGGING?: boolean
posthog?: posthog

View File

@ -1,31 +1,22 @@
import type { Meta, StoryObj } from '@storybook/react'
import { Marker } from 'maplibre-gl'
import { Map, MapComponent } from './Map'
import { Map } from './Map'
const coordinates: [number, number] = [0.119167, 52.205276]
const meta: Meta<typeof Map> = {
title: 'Components/Map',
component: Map,
tags: ['autodocs'],
}
type Story = StoryObj<typeof Map>
const coordinates: [number, number] = [0.119167, 52.205276]
export const Unavailable: Story = {}
export const Basic: Story = {
render: (args) => (
<MapComponent
mapLibreStyleUrl="" // TODO: set this value for the publish storybook and visual regression tests
{...args}
/>
),
// :TRICKY: We can't use markers in Storybook stories, as the Marker class is
// not JSON-serializable (circular structure).
args: {
center: coordinates,
markers: [new Marker({ color: 'var(--primary)' }).setLngLat(coordinates)],
className: 'h-60',
},
}
type Story = StoryObj<typeof Map>
export const Basic: Story = {}
export default meta

View File

@ -1,9 +1,23 @@
import { useEffect, useRef } from 'react'
import { Map as RawMap, Marker } from 'maplibre-gl'
import { useValues } from 'kea'
import maplibregl, { Map as RawMap, Marker } from 'maplibre-gl'
import { Protocol } from 'pmtiles'
import layers from 'protomaps-themes-base'
import useResizeObserver from 'use-resize-observer'
import 'maplibre-gl/dist/maplibre-gl.css'
import { themeLogic } from '~/layout/navigation-3000/themeLogic'
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
const protocol = new Protocol()
maplibregl.addProtocol('pmtiles', protocol.tile)
const BASE_URL = 'https://posthog-prod-maps.s3.us-east-1.amazonaws.com'
// :TRICKY: The URL absolutely needs to be prefixed with `pmtiles://` to work!
const PMTILES_URL = `pmtiles://${BASE_URL}/20230913.pmtiles`
const GLYPH_URL = `${BASE_URL}/fonts/pbf/{fontstack}/{range}.pbf`
/** Latitude and longtitude in degrees (+lat is east, -lat is west, +lon is south, -lon is north). */
export interface MapProps {
/** Coordinates to center the map on by default. */
@ -12,34 +26,45 @@ export interface MapProps {
markers?: Marker[]
/** Map container class names. */
className?: string
/** The map's MapLibre style. This must be a JSON object conforming to the schema described in the MapLibre Style Specification, or a URL to such JSON. */
mapLibreStyleUrl: string
}
export function Map({ className, ...rest }: Omit<MapProps, 'mapLibreStyleUrl'>): JSX.Element {
if (!window.JS_MAPLIBRE_STYLE_URL) {
export function Map({ className, ...rest }: MapProps): JSX.Element {
const { isCloudOrDev } = useValues(preflightLogic)
if (!isCloudOrDev) {
return (
<div className={`w-full h-full flex flex-col items-center justify-center text-muted p-3 ${className}`}>
<h1>Map unavailable</h1>
<p>
The <code>MAPLIBRE_STYLE_URL</code> setting is not defined. Please configure this setting with a
valid MapLibre Style URL to display maps.
</p>
<p>The map is currently only available in cloud deployments.</p>
</div>
)
}
return <MapComponent mapLibreStyleUrl={window.JS_MAPLIBRE_STYLE_URL} className={className} {...rest} />
return <MapComponent className={className} {...rest} />
}
export function MapComponent({ center, markers, className, mapLibreStyleUrl }: MapProps): JSX.Element {
export function MapComponent({ center, markers, className }: MapProps): JSX.Element {
const mapContainer = useRef<HTMLDivElement>(null)
const map = useRef<RawMap | null>(null)
const { isDarkModeOn } = useValues(themeLogic)
useEffect(() => {
map.current = new RawMap({
container: mapContainer.current as HTMLElement,
style: mapLibreStyleUrl,
style: {
version: 8,
glyphs: GLYPH_URL,
sources: {
protomaps: {
type: 'vector',
url: PMTILES_URL,
attribution:
'<a href="https://protomaps.com">Protomaps</a> © <a href="https://openstreetmap.org">OpenStreetMap</a>',
},
},
layers: layers('protomaps', isDarkModeOn ? 'dark' : 'light'),
},
center,
zoom: 4,
maxZoom: 10,

View File

@ -253,6 +253,12 @@ export const preflightLogic = kea<preflightLogicType>([
}))
},
],
isCloudOrDev: [
(s) => [s.preflight],
(preflight): boolean | undefined => {
return preflight?.cloud || preflight?.is_debug
},
],
}),
listeners(({ values, actions }) => ({
handlePreflightFinished: () => {

View File

@ -1,12 +1,17 @@
import { useValues } from 'kea'
import { PersonType } from '~/types'
import { Notebook } from 'scenes/notebooks/Notebook/Notebook'
import { uuid } from 'lib/utils'
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
type PersonFeedCanvasProps = {
person: PersonType
}
const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => {
const { isCloudOrDev } = useValues(preflightLogic)
const id = person.id
const personId = person.distinct_ids[0]
@ -32,10 +37,14 @@ const PersonFeedCanvas = ({ person }: PersonFeedCanvasProps): JSX.Element => {
type: 'ph-person',
attrs: { id: personId, nodeId: uuid(), title: 'Info' },
},
{
type: 'ph-map',
attrs: { id: personId, nodeId: uuid() },
},
...(isCloudOrDev
? [
{
type: 'ph-map',
attrs: { id: personId, nodeId: uuid() },
},
]
: []),
{
type: 'ph-properties',
attrs: { id: personId, nodeId: uuid() },

View File

@ -134,10 +134,12 @@
"md5": "^2.3.0",
"monaco-editor": "^0.39.0",
"papaparse": "^5.4.1",
"pmtiles": "^2.11.0",
"posthog-js": "1.87.4",
"posthog-js-lite": "2.0.0-alpha5",
"prettier": "^2.8.8",
"prop-types": "^15.7.2",
"protomaps-themes-base": "2.0.0-alpha.1",
"query-selector-shadow-dom": "^1.0.0",
"rc-field-form": "~1.21.0",
"rc-picker": "~2.5.17",

View File

@ -215,6 +215,9 @@ dependencies:
papaparse:
specifier: ^5.4.1
version: 5.4.1
pmtiles:
specifier: ^2.11.0
version: 2.11.0
posthog-js:
specifier: 1.87.4
version: 1.87.4
@ -227,6 +230,9 @@ dependencies:
prop-types:
specifier: ^15.7.2
version: 15.8.1
protomaps-themes-base:
specifier: 2.0.0-alpha.1
version: 2.0.0-alpha.1
query-selector-shadow-dom:
specifier: ^1.0.0
version: 1.0.0
@ -10671,6 +10677,10 @@ packages:
resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==}
dev: false
/fflate@0.8.1:
resolution: {integrity: sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==}
dev: false
/figures@3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'}
@ -15082,6 +15092,12 @@ packages:
semver-compare: 1.0.0
dev: true
/pmtiles@2.11.0:
resolution: {integrity: sha512-dU9SzzaqmCGpdEuTnIba6bDHT6j09ZJFIXxwGpvkiEnce3ZnBB1VKt6+EOmJGueriweaZLAMTUmKVElU2CBe0g==}
dependencies:
fflate: 0.8.1
dev: false
/pngjs@3.4.0:
resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==}
engines: {node: '>=4.0.0'}
@ -15751,6 +15767,10 @@ packages:
resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==}
dev: false
/protomaps-themes-base@2.0.0-alpha.1:
resolution: {integrity: sha512-eGAiUpBPAohnMvEHoF7NRWp7YuTNk/JsAVJ4733jqNw+/EF6Q5TMjqCOZScG3YSri5NStJg+9Upb95M2AQ3pjw==}
dev: false
/proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}

View File

@ -85,9 +85,6 @@ CAPTURE_TIME_TO_SEE_DATA = get_from_env("CAPTURE_TIME_TO_SEE_DATA", False, type_
# Whether kea should be act in verbose mode
KEA_VERBOSE_LOGGING = get_from_env("KEA_VERBOSE_LOGGING", False, type_cast=str_to_bool)
# MapLibre Style URL to configure map tile source
MAPLIBRE_STYLE_URL = get_from_env("MAPLIBRE_STYLE_URL", optional=True)
# Only written in specific scripts - do not use outside of them.
PERSON_ON_EVENTS_OVERRIDE = get_from_env("PERSON_ON_EVENTS_OVERRIDE", optional=True, type_cast=str_to_bool)

View File

@ -36,11 +36,6 @@
window.SENTRY_ENVIRONMENT = '{{ sentry_environment | escapejs }}';
</script>
{% endif %}
{% if js_maplibre_style_url %}
<script>
window.JS_MAPLIBRE_STYLE_URL = '{{ js_maplibre_style_url | escapejs }}'
</script>
{% endif %}
<script id='posthog-app-user-preload'>
window.POSTHOG_APP_CONTEXT = JSON.parse("{{ posthog_app_context | escapejs }}");
// Inject the expected location of JS bundle, use to allow the location of

View File

@ -344,9 +344,6 @@ def render_template(
context["js_kea_verbose_logging"] = settings.KEA_VERBOSE_LOGGING
context["js_url"] = get_js_url(request)
if settings.MAPLIBRE_STYLE_URL:
context["js_maplibre_style_url"] = settings.MAPLIBRE_STYLE_URL
posthog_app_context: Dict[str, Any] = {
"persisted_feature_flags": settings.PERSISTED_FEATURE_FLAGS,
"anonymous": not request.user or not request.user.is_authenticated,