mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
Merge pull request #1286 from asturksever/fix/since-note-inline
fix(street-level): SINCE note on the value's line: ANY DATE (by upload date)
This commit is contained in:
12 files changed
+50
-24
No files matched your search
@@ -425,7 +425,7 @@ _The Space Missions layer replaying a Falcon 9 ascent — labeled `RECONSTRUCTED
|
||||
|
||||
**Setup.** At [mapillary.com/dashboard/developers](https://www.mapillary.com/dashboard/developers), register an application with **Read** access and copy its **Client Token** (`MLY|…`). Paste it into **POWER UP → Mapillary**, or set `MAPILLARY_CLIENT_TOKEN` in `.env` and restart. Without it the panel reads **KEY REQUIRED**. **Google Street View** uses `GOOGLE_MAPS_API_KEY` with the **Maps JavaScript API** enabled for it in Google Cloud; its chip starts off, since every panorama is billed to the key. **KartaView** and **Panoramax** need nothing: their public APIs are keyless.
|
||||
|
||||
**Use.** Turn on **Street Level** under DATA LAYERS → Cameras, or with the pill in the STREET LEVEL panel header. Each provider has a chip in its own colour (Mapillary green), and one is lit at a time: lighting one switches the others off. Mapillary, which is free, is lit by default. Zoom in to street level (below 60 km) for the coverage lines; from orbit the panel says to zoom in. The **IMAGERY** (ALL / 360° / FLAT) and **SINCE** filters apply to Mapillary, KartaView and Panoramax; Street View panoramas are all 360°, so with Street View lit the filters are hidden. Click a coverage line for its image cones and a cone to open the photo. Light **KARTAVIEW** (purple) and zoom in below about 6 km: its lines are the streets KartaView has photos of, and a click on one opens the photo nearest the click, flat or 360° (drag to look around), with cones along its drive; **‹ ›** or ← → step through the drive (Shift+← →, ↑ ↓ and + − look around a 360° photo; pinch zooms on a phone). Photos KartaView has archived are skipped, and where all are archived the panel says so. For KartaView, **SINCE** goes by upload date, as KartaView's own map does (it can filter by nothing else), and the panel notes it under the slider; KartaView filters its lines on its own server, and a filtered area KartaView has not drawn before can take several seconds. Light **PANORAMAX** (orange) for the open, federated commons (strongest in France and Belgium): below about 60 km its lines are sequences. A click on a line opens that sequence's picture nearest the click without moving the camera, flat or 360°, with cones along the sequence around it; **‹ ›** or ← → step through it, and both filters apply. Its caption names the picture's authors (or the instance holding it) and licence (mostly CC BY-SA 4.0; pictures on the IGN instance are Licence Ouverte 2.0). On the **Google 3D** map (Google's terms keep Street View off other maps, where it does not appear), light **GOOGLE STREET VIEW** and click a street from below 3 km, or press **OPEN STREET VIEW** for the view centre, to open Google's panorama there; step along its arrows. Above the photo: **EXPAND** (full screen; Esc leaves) and **FIT / FILL** (Mapillary, and flat KartaView and Panoramax photos). The caption links to the image on the provider's site, and the globe credits each provider that is on ("© Mapillary contributors, CC BY-SA 4.0", "Street View imagery © Google", "© KartaView contributors, CC BY-SA 4.0", "© Panoramax contributors, licence per picture"). KartaView's own photo pages fail for signed-out visitors, so its link opens the full-size photo.
|
||||
**Use.** Turn on **Street Level** under DATA LAYERS → Cameras, or with the pill in the STREET LEVEL panel header. Each provider has a chip in its own colour (Mapillary green), and one is lit at a time: lighting one switches the others off. Mapillary, which is free, is lit by default. Zoom in to street level (below 60 km) for the coverage lines; from orbit the panel says to zoom in. The **IMAGERY** (ALL / 360° / FLAT) and **SINCE** filters apply to Mapillary, KartaView and Panoramax; Street View panoramas are all 360°, so with Street View lit the filters are hidden. Click a coverage line for its image cones and a cone to open the photo. Light **KARTAVIEW** (purple) and zoom in below about 6 km: its lines are the streets KartaView has photos of, and a click on one opens the photo nearest the click, flat or 360° (drag to look around), with cones along its drive; **‹ ›** or ← → step through the drive (Shift+← →, ↑ ↓ and + − look around a 360° photo; pinch zooms on a phone). Photos KartaView has archived are skipped, and where all are archived the panel says so. For KartaView, **SINCE** goes by upload date, as KartaView's own map does (it can filter by nothing else), and the panel notes it beside the SINCE value (ANY DATE (by upload date)); KartaView filters its lines on its own server, and a filtered area KartaView has not drawn before can take several seconds. Light **PANORAMAX** (orange) for the open, federated commons (strongest in France and Belgium): below about 60 km its lines are sequences. A click on a line opens that sequence's picture nearest the click without moving the camera, flat or 360°, with cones along the sequence around it; **‹ ›** or ← → step through it, and both filters apply. Its caption names the picture's authors (or the instance holding it) and licence (mostly CC BY-SA 4.0; pictures on the IGN instance are Licence Ouverte 2.0). On the **Google 3D** map (Google's terms keep Street View off other maps, where it does not appear), light **GOOGLE STREET VIEW** and click a street from below 3 km, or press **OPEN STREET VIEW** for the view centre, to open Google's panorama there; step along its arrows. Above the photo: **EXPAND** (full screen; Esc leaves) and **FIT / FILL** (Mapillary, and flat KartaView and Panoramax photos). The caption links to the image on the provider's site, and the globe credits each provider that is on ("© Mapillary contributors, CC BY-SA 4.0", "Street View imagery © Google", "© KartaView contributors, CC BY-SA 4.0", "© Panoramax contributors, licence per picture"). KartaView's own photo pages fail for signed-out visitors, so its link opens the full-size photo.
|
||||
|
||||
Share links carry the provider switches and filters (`0.m.0` Mapillary off, `0.m.0_0.r.google-1` Street View on, `0.m.0_0.r.google-0*kartaview-1*panoramax-0` KartaView on and `0.m.0_0.r.google-0*kartaview-0*panoramax-1` Panoramax on, as the app writes them (`0.m.0_0.r.kartaview-1` and `0.m.0_0.r.panoramax-1` work too; a link that leaves out `m` keeps Mapillary, the default, lit), `0.p.p` panoramas only, `0.s.365` the last year). To add a provider, implement the contract in `src/layers/streetLevel/registry.js` and register it in `src/app/layers/streetLevel.js`.
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
- The Street Level SINCE note sits on the value's line, in its type and a
|
||||
size smaller: with KartaView lit it reads ANY DATE (by upload date). It
|
||||
had lost its size variable in the Street Level slim-down and rendered
|
||||
larger than the value, on a line of its own (asturksever, #1286).
|
||||
@@ -3711,8 +3711,8 @@ lookup asks the photo API for the projection (`SPHERE`/`PLANE`; it ignores
|
||||
`fieldOfView`) and upload date and checks each answer the same way (when
|
||||
photos are near but none passes, the panel says so), and the cones pass on
|
||||
each photo's projection and upload date. The provider declares
|
||||
`sinceBasis: 'upload'`, so while it is lit the panel shows "KartaView: by
|
||||
upload date" under the SINCE slider (`sinceNote` in the UI state). Tiles come uncompressed and
|
||||
`sinceBasis: 'upload'`, so while it is lit the panel shows "(by
|
||||
upload date)" beside the SINCE value, as ANY DATE (by upload date) (`sinceNote` in the UI state). Tiles come uncompressed and
|
||||
uncacheable, so the last 24 decoded tiles are kept for 10 minutes while
|
||||
KartaView is lit (`createTileCache`, dropped when it is switched off); one
|
||||
that does not answer in 20 s is asked once more, and one that is not a line
|
||||
|
||||
@@ -945,7 +945,7 @@
|
||||
"Image by {creator}": "Imagen de {creator}",
|
||||
"zoom in to see KartaView coverage": "acércate para ver la cobertura de KartaView",
|
||||
"no KartaView photos in view": "no hay fotos de KartaView a la vista",
|
||||
"{names}: by upload date": "{names}: por fecha de subida",
|
||||
"(by upload date)": "(por fecha de subida)",
|
||||
"{n} streets in view · click a line for its nearest photo": {
|
||||
"one": "{n} calle a la vista · haz clic en una línea para su foto más cercana",
|
||||
"many": "{n} calles a la vista · haz clic en una línea para su foto más cercana",
|
||||
|
||||
@@ -954,7 +954,7 @@
|
||||
"Image by {creator}": "Автор снимка: {creator}",
|
||||
"zoom in to see KartaView coverage": "приблизьтесь, чтобы увидеть покрытие KartaView",
|
||||
"no KartaView photos in view": "фотографий KartaView в зоне видимости нет",
|
||||
"{names}: by upload date": "{names}: по дате загрузки",
|
||||
"(by upload date)": "(по дате загрузки)",
|
||||
"{n} streets in view · click a line for its nearest photo": {
|
||||
"one": "{n} улица в кадре · щёлкните линию, чтобы открыть ближайшую фотографию",
|
||||
"few": "{n} улицы в кадре · щёлкните линию, чтобы открыть ближайшую фотографию",
|
||||
|
||||
@@ -141,7 +141,7 @@ export const FILTERED_OUT_MESSAGE = msg(
|
||||
'None of KartaView’s photos here pass the imagery filter',
|
||||
);
|
||||
/** Under the SINCE slider while KartaView is lit. */
|
||||
export const SINCE_NOTE = 'KartaView: by upload date';
|
||||
export const SINCE_NOTE = '(by upload date)';
|
||||
|
||||
/** The UTC calendar day of `ms`, as KartaView's startDate reads it. */
|
||||
function utcDay(ms) {
|
||||
|
||||
@@ -23,7 +23,7 @@ export function filtersOf(provider) {
|
||||
* @property {{kind: 'view-cone', color: string}} [marker] Default: GEV's pin.
|
||||
* @property {Array<'pano'|'since'>} [filters] Filters it honours (default both).
|
||||
* @property {{noun: string, action: string}} [coverageLabel] How the panel counts its lines and says what a click does (default: sequences, "click a line for its photos").
|
||||
* @property {'capture'|'upload'} [sinceBasis] What SINCE compares (default 'capture'); 'upload' puts a note under the slider while the provider is lit.
|
||||
* @property {'capture'|'upload'} [sinceBasis] What SINCE compares (default 'capture'); 'upload' notes "(by upload date)" beside the SINCE value while the provider is lit.
|
||||
* @property {(context: ProviderContext) => ProviderInstance} create
|
||||
*
|
||||
* @typedef {object} ProviderContext Handed to `create()` once by the core.
|
||||
|
||||
@@ -73,16 +73,14 @@ export function filterControls(providers) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The note under SINCE when a lit provider dates its imagery by upload,
|
||||
* e.g. "KartaView: by upload date", or null.
|
||||
* The note beside the SINCE value when a lit provider dates its imagery by
|
||||
* upload, "(by upload date)", or null. One source is lit at a time, so the
|
||||
* note needs no provider name.
|
||||
* @param {Array<ProviderSnapshot>} providers
|
||||
*/
|
||||
export function sinceNote(providers) {
|
||||
const names = providers
|
||||
.filter((p) => p.on && p.sinceBasis === 'upload')
|
||||
.map((p) => p.name);
|
||||
return names.length
|
||||
? t('{names}: by upload date', { names: names.join(', ') })
|
||||
return providers.some((p) => p.on && p.sinceBasis === 'upload')
|
||||
? t('(by upload date)')
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ test('the filter controls show only for a lit provider that honours them', () =>
|
||||
);
|
||||
});
|
||||
|
||||
test('a lit provider that dates by upload puts a note under SINCE', () => {
|
||||
test('a lit provider that dates by upload notes it beside the SINCE value', () => {
|
||||
const kartaView = provider({
|
||||
id: 'kartaview',
|
||||
name: 'KartaView',
|
||||
@@ -75,7 +75,7 @@ test('a lit provider that dates by upload puts a note under SINCE', () => {
|
||||
});
|
||||
const note = (providers) => composeUIState({ ...base, providers }).sinceNote;
|
||||
assert.equal(note([provider()]), null, 'Mapillary: capture date');
|
||||
assert.equal(note([kartaView]), 'KartaView: by upload date');
|
||||
assert.equal(note([kartaView]), '(by upload date)');
|
||||
assert.equal(note([{ ...kartaView, on: false }]), null, 'only while lit');
|
||||
});
|
||||
|
||||
|
||||
@@ -981,9 +981,9 @@ test('a note under SINCE says what date it compares, only while one is given', (
|
||||
const { layer } = stubPanel(dom, state);
|
||||
const note = () => dom.root.querySelector('#sl-since-note');
|
||||
assert.equal(note().hidden, true, 'none for Mapillary');
|
||||
layer.publish({ ...state, sinceNote: 'KartaView: by upload date' });
|
||||
layer.publish({ ...state, sinceNote: '(by upload date)' });
|
||||
assert.equal(note().hidden, false);
|
||||
assert.equal(note().textContent, 'KartaView: by upload date');
|
||||
assert.equal(note().textContent, '(by upload date)');
|
||||
layer.publish(state);
|
||||
assert.equal(note().hidden, true);
|
||||
// The panel's own markup has it, read out with the slider.
|
||||
|
||||
@@ -236,10 +236,33 @@ html:not([lang='en']) .sl-meta-row .sl-nearest-btn {
|
||||
gap: 4px 10px;
|
||||
}
|
||||
|
||||
.sl-since-note {
|
||||
.sl-range {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
accent-color: var(--sl-green);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.sl-range:focus-visible {
|
||||
outline: 1px solid var(--accent);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
/* The value and its note share a line: ANY DATE (by upload date). */
|
||||
.sl-since-value {
|
||||
grid-column: 2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
gap: 0 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.sl-since-note {
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--sl-text-small);
|
||||
font-size: 0.5rem;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
@@ -248,7 +271,6 @@ html:not([lang='en']) .sl-meta-row .sl-nearest-btn {
|
||||
}
|
||||
|
||||
.sl-since-label {
|
||||
grid-column: 2;
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--sl-text);
|
||||
letter-spacing: 0.08em;
|
||||
|
||||
@@ -126,9 +126,11 @@
|
||||
</div>
|
||||
<div id="sl-since-row" class="sl-since">
|
||||
<label class="cctv-summary-label" for="sl-since" data-i18n>SINCE</label>
|
||||
<input id="sl-since" class="gev-quantitative-slider sl-range" type="range" min="0" max="8" step="1" value="0" aria-valuetext="ANY DATE" aria-describedby="sl-since-label sl-since-note" />
|
||||
<output id="sl-since-label" class="sl-since-label" for="sl-since" data-i18n>ANY DATE</output>
|
||||
<small id="sl-since-note" class="sl-since-note" hidden></small>
|
||||
<input id="sl-since" class="sl-range" type="range" min="0" max="8" step="1" value="0" aria-valuetext="ANY DATE" aria-describedby="sl-since-label sl-since-note" />
|
||||
<span class="sl-since-value">
|
||||
<output id="sl-since-label" class="sl-since-label" for="sl-since" data-i18n>ANY DATE</output>
|
||||
<small id="sl-since-note" class="sl-since-note" hidden></small>
|
||||
</span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<!-- The hint says how to open imagery; the button does it without a pointer. -->
|
||||
|
||||
Reference in new issue
Block a user