Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
f5838b6
Add command
gjmooney Oct 24, 2025
503143d
Add landmarks as a layer
gjmooney Oct 24, 2025
d222763
Move to landmark wip
gjmooney Oct 24, 2025
735c325
Add a zoom to layer button
gjmooney Oct 28, 2025
cfabfda
Add a story map thing to the file
gjmooney Oct 28, 2025
fea7c85
Add temp button to create story
gjmooney Oct 28, 2025
387aa15
Add story creation method to model
gjmooney Oct 28, 2025
befa7f7
Add story editing(?) panel
gjmooney Oct 28, 2025
34e84d3
Rename panel
gjmooney Oct 28, 2025
011a80c
Add storiesMap to file
gjmooney Oct 29, 2025
1513030
Add some panels
gjmooney Oct 29, 2025
48811d2
Add temp viewer panel
gjmooney Oct 29, 2025
6d9b67b
Start implementing story viewer
gjmooney Oct 29, 2025
7702a59
Use textarea for markdown field
gjmooney Oct 29, 2025
81ef9e3
Push zoom button to right side
gjmooney Oct 29, 2025
9400e4a
Only support one story
gjmooney Nov 3, 2025
ee4fe7c
Handle story signal stuff
gjmooney Nov 3, 2025
a375381
Update landmark order when drag and dropping
gjmooney Nov 4, 2025
f2d10b1
Update viewer order based on list order
gjmooney Nov 4, 2025
0bd91b4
Tidy
gjmooney Nov 4, 2025
f2c74ae
Hack story selection
gjmooney Nov 4, 2025
b6bd6d6
Effect cleaning
gjmooney Nov 4, 2025
001efa7
Return ID as well
gjmooney Nov 4, 2025
16c28a1
Refactor viewer panel
gjmooney Nov 4, 2025
244dc7b
Refactor editor panel
gjmooney Nov 4, 2025
9928a05
Dont reverse landmark list
gjmooney Nov 5, 2025
6b35474
Update viewer content when selecting landmarks
gjmooney Nov 5, 2025
b741854
Remove rank from schema
gjmooney Nov 5, 2025
c6fec02
Update viewer panel style
gjmooney Nov 5, 2025
ec20e15
Move to position when clicking landmark in unguided tour
gjmooney Nov 5, 2025
65faea0
Remove zoomies
gjmooney Nov 5, 2025
2fe796d
Fix status bar loading when adding landmark
gjmooney Nov 6, 2025
c2eafaa
Use one panel for both story panels
gjmooney Nov 6, 2025
6c942a2
Refactor editor panel
gjmooney Nov 7, 2025
96cd9a9
Remove stray console logs
gjmooney Nov 7, 2025
75fca1f
Add story presentation as a setting
gjmooney Nov 7, 2025
5bc7621
Add presentation flags to side panels
gjmooney Nov 7, 2025
45baac0
Some styling
gjmooney Nov 10, 2025
1e1532a
see ess ess
gjmooney Nov 11, 2025
5acec1f
Add button to recenter landmark
gjmooney Nov 14, 2025
5148862
Remove hardcoded id
gjmooney Nov 17, 2025
94f7094
Clean up
gjmooney Nov 19, 2025
9facd18
Format-on-save, why hast thou forsaken me?
gjmooney Nov 19, 2025
93cd216
Landmark icon
gjmooney Nov 20, 2025
717aea3
Allow customization for transition animations
gjmooney Nov 20, 2025
284a7a5
Change preview button to a switch
gjmooney Nov 20, 2025
2805908
Move nav buttons
gjmooney Nov 20, 2025
c37e732
Cancel animations before starting another
gjmooney Nov 20, 2025
c06d2f8
Remove landmarks item from story editor form
gjmooney Nov 25, 2025
73e5027
Restore zoomies
gjmooney Nov 25, 2025
61524de
Replace visibility toggle with slide number indicator
gjmooney Nov 25, 2025
db1ea99
Move transition settings to landmark
gjmooney Nov 25, 2025
ffd17cd
Select layer when moving through story; Move CSS to classes
gjmooney Nov 25, 2025
9817540
Better nav button styles
gjmooney Nov 25, 2025
fefd962
Get story when mounting component
gjmooney Nov 25, 2025
4f50b16
Change default button border color
gjmooney Nov 25, 2025
219469e
Add form button to update extent and zoom of landmark
gjmooney Nov 25, 2025
d25bb5a
Add padding
gjmooney Nov 26, 2025
cc9487f
GOOD rebase
gjmooney Nov 26, 2025
0cbdb0d
Preload image in case link is bad
gjmooney Dec 2, 2025
da35d94
Rename storiesMap
gjmooney Dec 2, 2025
4cac410
Change landmark extent button text
gjmooney Dec 2, 2025
ca0038d
Dont display slide number if layerName is defined
gjmooney Dec 2, 2025
48b78b5
Change add landmark label
gjmooney Dec 2, 2025
c992b65
Add add landmark option to layer context menu
gjmooney Dec 3, 2025
91c2319
Change add landmark command label wording
gjmooney Dec 3, 2025
4ca911a
Fix disabling object properties in presentation mode
gjmooney Dec 3, 2025
4a95116
Invert presentation mode setting
gjmooney Dec 3, 2025
e154364
Fix overwriting values on opening file
gjmooney Dec 3, 2025
b5fd251
Add Story Map example
gjmooney Dec 3, 2025
7d3b6a8
Stop console spam
gjmooney Dec 3, 2025
0162052
Zoom out more on smooth transitions
gjmooney Dec 3, 2025
46c23ba
Change layer name
gjmooney Dec 3, 2025
b24c6a5
Another GOOD rebase
gjmooney Dec 3, 2025
600a1b0
Why were these snapshots so old
gjmooney Dec 4, 2025
059a30f
Update lockfile
gjmooney Dec 5, 2025
c5b83be
Lint
gjmooney Dec 5, 2025
d2845ba
Bot missed some snapshots, expected ones still had undo/redo
gjmooney Dec 8, 2025
c4947d9
Update Playwright Snapshots
github-actions[bot] Dec 8, 2025
e9b9522
Update Playwright Snapshots
github-actions[bot] Dec 8, 2025
06305a9
Test
gjmooney Dec 9, 2025
1f91c4e
Change UI text to use Segment instead of landmark
gjmooney Dec 10, 2025
b6a4c59
add button
gjmooney Dec 10, 2025
fba1980
Give model addStorySegment method
gjmooney Dec 10, 2025
89bec5d
Lint
gjmooney Dec 10, 2025
586cc6a
Update Playwright Snapshots
github-actions[bot] Dec 10, 2025
886a827
Landmark -> Story Segment
gjmooney Dec 10, 2025
b634016
Lint
gjmooney Dec 10, 2025
641ed7e
Update example
gjmooney Dec 10, 2025
7bb5d8c
Bot on bot violence
gjmooney Dec 11, 2025
80f7f74
Update settings/options
gjmooney Dec 11, 2025
e1a0f00
Use story mode setting and option to update UI
gjmooney Dec 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 212 additions & 0 deletions examples/story_map.jGIS
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
{
"layerTree": [
"5d10a9ba-eeef-486d-9761-33ff1ba4106e",
"5f790e80-230b-4c00-8426-b3a9385937a5",
"8591b32f-11c0-4d70-a997-e94d258bb100",
"bcd22241-e404-44b4-873b-81e6a4ccad84",
"5862186d-0cae-4cee-be39-18951e31030f",
"aabaa10b-4a6f-4a24-9ead-6f17bb7f2f7d",
"93080edc-815f-4364-a874-90fd53a60c35"
],
"layers": {
"5862186d-0cae-4cee-be39-18951e31030f": {
"name": "The Redeemer",
"parameters": {
"opacity": 1.0,
"source": "a7e1fc1e-1ab9-461f-89cb-2010c790062f",
"symbologyState": {
"renderType": "Single Symbol"
}
},
"type": "VectorLayer",
"visible": true
},
"5d10a9ba-eeef-486d-9761-33ff1ba4106e": {
"name": "OpenStreetMap.Mapnik Layer",
"parameters": {
"extent": [
-7248097.58721681,
-743268.1554684378,
-6334954.257801768,
-303993.91946789756
],
"opacity": 1.0,
"source": "32431800-9aad-4702-926b-52fcdce5530e",
"zoom": 7.604194565762505
},
"type": "RasterLayer",
"visible": true
},
"5f790e80-230b-4c00-8426-b3a9385937a5": {
"name": "Cristo Redentor",
"parameters": {
"content": {
"image": "https://images.pexels.com/photos/2771080/pexels-photo-2771080.jpeg",
"markdown": "**Christ the Redeemer** (Portuguese: *Cristo Redentor*, standard Brazilian Portuguese: [\u02c8k\u027eistu \u0281ed\u1ebd\u02c8to\u0281]) is an Art Deco statue of Jesus in Rio de Janeiro, Brazil, created by French-Polish sculptor Paul Landowski and built by Brazilian engineer Heitor da Silva Costa, in collaboration with French engineer Albert Caquot.",
"title": "The Redeemer"
},
"extent": [
-4814802.663104911,
-2630126.461218188,
-4804544.428248574,
-2622570.615984798
],
"transition": {
"time": 2.0,
"type": "smooth"
},
"zoom": 14.080181481426658
},
"type": "StorySegmentLayer",
"visible": true
},
"8591b32f-11c0-4d70-a997-e94d258bb100": {
"name": "La Libert\u00e9 \u00e9clairant le monde",
"parameters": {
"content": {
"image": "https://images.pexels.com/photos/356844/pexels-photo-356844.jpeg",
"markdown": "**The Statue of Liberty** (Liberty Enlightening the World; French: *La Libert\u00e9 \u00e9clairant le monde*) is a colossal neoclassical sculpture of a robed and crowned female on Liberty Island in New York Harbor, within New York City.",
"title": "The Statue of Liberty"
},
"extent": [
-8244347.787989774,
4964878.911422763,
-8240146.493537257,
4967973.433151666
],
"transition": {
"time": 2.0,
"type": "smooth"
},
"zoom": 15.368058180489786
},
"type": "StorySegmentLayer",
"visible": true
},
"93080edc-815f-4364-a874-90fd53a60c35": {
"name": "The Thinker",
"parameters": {
"opacity": 1.0,
"source": "19ef5002-5670-4c17-b53f-44a48b739158",
"symbologyState": {
"renderType": "Single Symbol"
}
},
"type": "VectorLayer",
"visible": true
},
"aabaa10b-4a6f-4a24-9ead-6f17bb7f2f7d": {
"name": "Statue of Liberty",
"parameters": {
"opacity": 1.0,
"source": "660bb0bb-e0ce-4692-a7c7-119829d6e0d1",
"symbologyState": {
"renderType": "Single Symbol"
}
},
"type": "VectorLayer",
"visible": true
},
"bcd22241-e404-44b4-873b-81e6a4ccad84": {
"name": "Le Penseur",
"parameters": {
"content": {
"image": "https://images.pexels.com/photos/6486115/pexels-photo-6486115.jpeg",
"markdown": "**The Thinker** (French: *Le Penseur*), by Auguste Rodin, is a bronze sculpture depicting a nude male figure of heroic size, seated on a large rock, leaning forward, his right elbow placed upon his left thigh, with the back of his right hand supporting his chin in a posture evocative of deep thought and contemplation.",
"title": "The Thinker"
},
"extent": [
255360.959592592,
6248688.604308756,
261009.190947415,
6252093.017728101
],
"transition": {
"time": 2.0,
"type": "smooth"
},
"zoom": 15.230368389488868
},
"type": "StorySegmentLayer",
"visible": true
}
},
"metadata": {},
"options": {
"bearing": 0.0,
"extent": [
256226.31587442243,
6249293.335639825,
260143.83466558298,
6251488.286397034
],
"latitude": 48.855574302496535,
"longitude": 2.319315992465925,
"pitch": 0.0,
"projection": "EPSG:3857",
"zoom": 15.230368389488868
},
"schemaVersion": "0.5.0",
"sources": {
"19ef5002-5670-4c17-b53f-44a48b739158": {
"name": "Marker",
"parameters": {
"feature": {
"coords": [
257771.740387152,
6250219.77589449
]
}
},
"type": "MarkerSource"
},
"32431800-9aad-4702-926b-52fcdce5530e": {
"name": "OpenStreetMap.Mapnik",
"parameters": {
"attribution": "(C) OpenStreetMap contributors",
"interpolate": false,
"maxZoom": 19.0,
"minZoom": 0.0,
"provider": "OpenStreetMap",
"url": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"urlParameters": {}
},
"type": "RasterSource"
},
"660bb0bb-e0ce-4692-a7c7-119829d6e0d1": {
"name": "Marker",
"parameters": {
"feature": {
"coords": [
-8242685.709008398,
4966710.369862526
]
}
},
"type": "MarkerSource"
},
"a7e1fc1e-1ab9-461f-89cb-2010c790062f": {
"name": "Marker",
"parameters": {
"feature": {
"coords": [
-4810184.197896464,
-2626176.8148461888
]
}
},
"type": "MarkerSource"
}
},
"stories": {
"1b181980-a95a-4f23-8e5d-980c66ff93ea": {
"storySegments": [
"5f790e80-230b-4c00-8426-b3a9385937a5",
"8591b32f-11c0-4d70-a997-e94d258bb100",
"bcd22241-e404-44b4-873b-81e6a4ccad84"
],
"storyType": "guided",
"title": "Famous Statues"
}
}
}
2 changes: 2 additions & 0 deletions packages/base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-popover": "^1.1.14",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-toggle-group": "^1.1.10",
"@rjsf/core": "^4.2.0",
Expand All @@ -93,6 +94,7 @@
"proj4-list": "1.0.4",
"react": "^18.0.1",
"react-day-picker": "^9.7.0",
"react-markdown": "^10.1.0",
"shpjs": "^6.1.0",
"styled-components": "^5.3.6",
"three": "^0.135.0",
Expand Down
3 changes: 3 additions & 0 deletions packages/base/src/commands/BaseCommandIDs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,6 @@ export const showFiltersTab = 'jupytergis:showFiltersTab';
export const showObjectPropertiesTab = 'jupytergis:showObjectPropertiesTab';
export const showAnnotationsTab = 'jupytergis:showAnnotationsTab';
export const showIdentifyPanelTab = 'jupytergis:showIdentifyPanelTab';

// Story maps
export const addStorySegment = 'jupytergis:addStorySegment';
22 changes: 22 additions & 0 deletions packages/base/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,28 @@ export function addCommands(
...icons.get(CommandIDs.addMarker),
});

commands.addCommand(CommandIDs.addStorySegment, {
label: trans.__('Add Story Segment'),
isEnabled: () => {
const current = tracker.currentWidget;
if (!current) {
return false;
}
return (
current.model.sharedModel.editable &&
!current.model.jgisSettings.storyMapsDisabled
);
},
execute: args => {
const current = tracker.currentWidget;
if (!current) {
return;
}
current.model.addStorySegment();
},
...icons.get(CommandIDs.addStorySegment),
});

loadKeybindings(commands, keybindings);
}

Expand Down
1 change: 1 addition & 0 deletions packages/base/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const iconObject = {
[CommandIDs.identify]: { icon: infoIcon },
[CommandIDs.temporalController]: { icon: clockIcon },
[CommandIDs.addMarker]: { icon: markerIcon },
[CommandIDs.addStorySegment]: { iconClass: 'fa fa-link' },
};

/**
Expand Down
6 changes: 6 additions & 0 deletions packages/base/src/formbuilder/formselectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { LayerType, SourceType } from '@jupytergis/schema';
import {
HeatmapLayerPropertiesForm,
HillshadeLayerPropertiesForm,
StorySegmentLayerPropertiesForm,
LayerPropertiesForm,
VectorLayerPropertiesForm,
WebGlLayerPropertiesForm,
Expand Down Expand Up @@ -33,6 +34,11 @@ export function getLayerTypeForm(
break;
case 'HeatmapLayer':
LayerForm = HeatmapLayerPropertiesForm;
break;
case 'StorySegmentLayer':
LayerForm = StorySegmentLayerPropertiesForm;
break;

// ADD MORE FORM TYPES HERE
}

Expand Down
17 changes: 17 additions & 0 deletions packages/base/src/formbuilder/objectform/StoryEditorForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { IDict } from '@jupytergis/schema';

import { BaseForm } from './baseform';

/**
* The form to modify a hillshade layer.
*/
export class StoryEditorPropertiesForm extends BaseForm {
protected processSchema(
data: IDict<any> | undefined,
schema: IDict,
uiSchema: IDict,
) {
super.processSchema(data, schema, uiSchema);
this.removeFormEntry('storySegments', data, schema, uiSchema);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { IJupyterGISModel } from '@jupytergis/schema';
import { LabIcon } from '@jupyterlab/ui-components';
import React from 'react';

import { targetWithCenterIcon } from '@/src/icons';
import { Button } from '@/src/shared/components/Button';

interface IStorySegmentResetProps {
model?: IJupyterGISModel;
layerId?: string;
}

function StorySegmentReset({ model, layerId }: IStorySegmentResetProps) {
const handleSetStorySegmentToCurrentView = () => {
if (!model || !layerId) {
return;
}
const layer = model.getLayer(layerId);
if (!layer) {
return;
}
const { zoom, extent } = model.getOptions();
const updatedLayer = {
...layer,
parameters: {
...layer.parameters,
zoom,
extent,
},
};

model.sharedModel.updateLayer(layerId, updatedLayer);
};

return (
<div>
<Button
title="Set story segment to current viewport"
onClick={handleSetStorySegmentToCurrentView}
>
<LabIcon.resolveReact
icon={targetWithCenterIcon}
className="jp-gis-layerIcon"
tag="span"
/>
Set Story Segment Extent
</Button>
</div>
);
}

export default StorySegmentReset;
1 change: 1 addition & 0 deletions packages/base/src/formbuilder/objectform/layer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './hillshadeLayerForm';
export * from './layerform';
export * from './vectorlayerform';
export * from './webGlLayerForm';
export * from './storySegmentLayerForm';
Loading
Loading