mirror of
https://github.com/hyperknot/openfreemap.git
synced 2026-05-21 14:02:15 +00:00
work
This commit is contained in:
@@ -7,8 +7,53 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||||
<link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet" />
|
<link href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" rel="stylesheet" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="flex flex-col h-screen">
|
||||||
<div id="map" class="w-full h-screen"></div>
|
<!-- UI Panel -->
|
||||||
|
<div class="bg-gray-900 border-b border-gray-700 shadow-md">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 py-2">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="flex-1">
|
||||||
|
<label for="line1" class="block text-xs font-medium text-gray-400 mb-1">
|
||||||
|
Line 1
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="line1"
|
||||||
|
class="w-full px-3 py-1.5 text-sm border border-gray-600 rounded bg-gray-800 text-gray-100 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all font-mono"
|
||||||
|
placeholder="underscore,colon,name,latin"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1">
|
||||||
|
<label for="line2" class="block text-xs font-medium text-gray-400 mb-1">
|
||||||
|
Line 2
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="line2"
|
||||||
|
class="w-full px-3 py-1.5 text-sm border border-gray-600 rounded bg-gray-800 text-gray-100 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all font-mono"
|
||||||
|
placeholder="nonlatin"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="w-24">
|
||||||
|
<label for="lang" class="block text-xs font-medium text-gray-400 mb-1">
|
||||||
|
Lang
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="lang"
|
||||||
|
class="w-full px-3 py-1.5 text-sm border border-gray-600 rounded bg-gray-800 text-gray-100 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-all font-mono text-center"
|
||||||
|
placeholder="en"
|
||||||
|
maxlength="5"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="map" class="flex-1"></div>
|
||||||
|
|
||||||
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
|
<script src="https://unpkg.com/maplibre-gl/dist/maplibre-gl.js"></script>
|
||||||
<script src="mix.js"></script>
|
<script src="mix.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,16 +1,59 @@
|
|||||||
const map = new maplibregl.Map({
|
const map = new maplibregl.Map({
|
||||||
container: 'map',
|
container: 'map',
|
||||||
hash: 'map',
|
|
||||||
style: 'https://tiles.openfreemap.org/styles/liberty',
|
style: 'https://tiles.openfreemap.org/styles/liberty',
|
||||||
center: [0, 0],
|
center: [0, 0],
|
||||||
zoom: 2,
|
zoom: 2,
|
||||||
})
|
})
|
||||||
|
|
||||||
function modifyStyle({ style, langCode }) {
|
const line1Input = document.getElementById('line1')
|
||||||
if (!langCode) {
|
const line2Input = document.getElementById('line2')
|
||||||
langCode = 'en'
|
const langInput = document.getElementById('lang')
|
||||||
|
|
||||||
|
// Parse URL search params to get line1 and line2
|
||||||
|
function parseParams() {
|
||||||
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
return {
|
||||||
|
line1: params.get('line1') || 'underscore,colon,name,latin',
|
||||||
|
line2: params.get('line2') || 'nonlatin',
|
||||||
|
lang: params.get('lang') || 'en',
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update URL search params
|
||||||
|
function updateParams(line1, line2, lang) {
|
||||||
|
const url = new URL(window.location)
|
||||||
|
url.searchParams.set('line1', line1)
|
||||||
|
url.searchParams.set('line2', line2)
|
||||||
|
url.searchParams.set('lang', lang)
|
||||||
|
window.history.replaceState({}, '', url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build field accessor from config string
|
||||||
|
function buildFieldAccessor(config, langCode) {
|
||||||
|
const parts = []
|
||||||
|
const fields = config.split(',').map(f => f.trim()).filter(f => f)
|
||||||
|
|
||||||
|
for (const field of fields) {
|
||||||
|
if (field === 'underscore') {
|
||||||
|
parts.push(['get', `name_${langCode}`])
|
||||||
|
} else if (field === 'colon') {
|
||||||
|
parts.push(['get', `name:${langCode}`])
|
||||||
|
} else if (field === 'name') {
|
||||||
|
parts.push(['get', 'name'])
|
||||||
|
} else if (field === 'latin') {
|
||||||
|
parts.push(['get', 'name:latin'])
|
||||||
|
} else if (field === 'nonlatin') {
|
||||||
|
parts.push(['get', 'name:nonlatin'])
|
||||||
|
} else {
|
||||||
|
// Custom field name
|
||||||
|
parts.push(['get', field])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.length > 0 ? ['coalesce', ...parts] : ['get', 'name']
|
||||||
|
}
|
||||||
|
|
||||||
|
function modifyStyle({ style, line1Config, line2Config, langCode }) {
|
||||||
for (const layer of style.layers) {
|
for (const layer of style.layers) {
|
||||||
if (layer.source !== 'openmaptiles') continue
|
if (layer.source !== 'openmaptiles') continue
|
||||||
if (!layer.layout) continue
|
if (!layer.layout) continue
|
||||||
@@ -18,49 +61,80 @@ function modifyStyle({ style, langCode }) {
|
|||||||
const textField = layer.layout['text-field']
|
const textField = layer.layout['text-field']
|
||||||
if (!textField) continue
|
if (!textField) continue
|
||||||
|
|
||||||
// highway numbers, etc. - skip ref-only fields
|
// Skip ref-only fields
|
||||||
if (JSON.stringify(textField) === JSON.stringify(['to-string', ['get', 'ref']])) continue
|
if (JSON.stringify(textField) === JSON.stringify(['to-string', ['get', 'ref']])) continue
|
||||||
|
|
||||||
const nameUnderscore = `name_${langCode}`
|
const id = layer.id
|
||||||
const nameColon = `name:${langCode}`
|
let separator = id.includes('line') || id.includes('highway') ? ' ' : '\n'
|
||||||
|
|
||||||
// Always display both values
|
const line1Expr = buildFieldAccessor(line1Config, langCode)
|
||||||
layer.layout['text-field'] = ['concat', ['get', nameUnderscore], '\n', ['get', nameColon]]
|
const line2Expr = buildFieldAccessor(line2Config, langCode)
|
||||||
|
|
||||||
// Color red when they are different
|
// Combine both lines
|
||||||
if (!layer.paint) layer.paint = {}
|
layer.layout['text-field'] = ['concat', line1Expr, separator, line2Expr]
|
||||||
layer.paint['text-color'] = [
|
|
||||||
'case',
|
|
||||||
['!=', ['get', nameUnderscore], ['get', nameColon]],
|
|
||||||
'#ff0000', // Red when different
|
|
||||||
'#000000', // Default color when same (adjust as needed)
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyLanguage() {
|
function applyConfiguration() {
|
||||||
const hash = window.location.hash.substring(1) // Remove the '#'
|
const { line1, line2, lang } = parseParams()
|
||||||
const langCode = hash || null
|
|
||||||
|
if (!map.getStyle()) return
|
||||||
|
|
||||||
const style = map.getStyle()
|
const style = map.getStyle()
|
||||||
modifyStyle({ style, langCode })
|
modifyStyle({ style, line1Config: line1, line2Config: line2, langCode: lang })
|
||||||
map.setStyle(style, { diff: false })
|
map.setStyle(style, { diff: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
map.on('load', () => {
|
function syncInputsFromParams() {
|
||||||
// Add default hash if not present
|
const { line1, line2, lang } = parseParams()
|
||||||
if (!window.location.hash) {
|
line1Input.value = line1
|
||||||
alert(
|
line2Input.value = line2
|
||||||
'To change the map language, modify the language code in the URL #.\nLabels will be RED when different.\nname_xx on line 1, name:xx on line 2',
|
langInput.value = lang
|
||||||
)
|
|
||||||
window.location.hash = '#en'
|
|
||||||
// The hashchange event will trigger applyLanguage()
|
|
||||||
} else {
|
|
||||||
applyLanguage()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update params when inputs change
|
||||||
|
line1Input.addEventListener('input', () => {
|
||||||
|
updateParams(line1Input.value, line2Input.value, langInput.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Listen for hash changes in URL
|
line2Input.addEventListener('input', () => {
|
||||||
window.addEventListener('hashchange', () => {
|
updateParams(line1Input.value, line2Input.value, langInput.value)
|
||||||
applyLanguage()
|
})
|
||||||
|
|
||||||
|
langInput.addEventListener('input', () => {
|
||||||
|
updateParams(line1Input.value, line2Input.value, langInput.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Apply configuration when Enter is pressed
|
||||||
|
line1Input.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') applyConfiguration()
|
||||||
|
})
|
||||||
|
|
||||||
|
line2Input.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') applyConfiguration()
|
||||||
|
})
|
||||||
|
|
||||||
|
langInput.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') applyConfiguration()
|
||||||
|
})
|
||||||
|
|
||||||
|
map.on('load', () => {
|
||||||
|
// Initialize params if not present
|
||||||
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
if (!params.has('line1') || !params.has('line2') || !params.has('lang')) {
|
||||||
|
const url = new URL(window.location)
|
||||||
|
if (!params.has('line1')) url.searchParams.set('line1', 'underscore,colon,name,latin')
|
||||||
|
if (!params.has('line2')) url.searchParams.set('line2', 'nonlatin')
|
||||||
|
if (!params.has('lang')) url.searchParams.set('lang', 'en')
|
||||||
|
window.history.replaceState({}, '', url)
|
||||||
|
}
|
||||||
|
|
||||||
|
syncInputsFromParams()
|
||||||
|
applyConfiguration()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Listen for URL changes (e.g., browser back/forward)
|
||||||
|
window.addEventListener('popstate', () => {
|
||||||
|
syncInputsFromParams()
|
||||||
|
applyConfiguration()
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user