Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade OpenLayers to v9 #868

Merged
merged 28 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
17c8a3a
Migrate canvas source and polygon brush from @biigle/ol to core
mzur Jun 27, 2024
f2853bf
WIP Upgrade to OpenLayers v6
mzur Jun 28, 2024
7dda9c0
Improve video (minimap) rendering
mzur Jul 2, 2024
57db566
Fix size of OpenLayers controls
mzur Jul 2, 2024
04bbea8
Fix magic wand snapshot update behavior
mzur Jul 2, 2024
c5bb3d5
Remove unnecessary fallback
mzur Jul 2, 2024
5724449
Upgrade to OpenLayers v7
mzur Jul 3, 2024
a1b0242
Fix OpenLayers control style
mzur Jul 3, 2024
b6f7656
Upgrade to OpenLayers v9
mzur Jul 3, 2024
f190f71
Fix issues because minimap made OpenLayers map reactive
mzur Jul 3, 2024
2499167
Improve performance of polygon brush and modify brush interactions
mzur Jul 3, 2024
9a4cddd
Remove unnecessary option
mzur Jul 3, 2024
f47de14
Upgrade to OpenLayers v9 (for real)
mzur Jul 3, 2024
1f3f094
Fix screenshot button behavior
mzur Jul 4, 2024
f473700
Fix minimap update on color adjustment
mzur Jul 4, 2024
708fd0d
Fix padding of zoom to whole image interaction
mzur Jul 4, 2024
03ee712
Fix select interaction behavior
mzur Jul 5, 2024
6b45674
Fix flickering minimap with tiled image
mzur Jul 5, 2024
61c6bcd
Fix ESLint errors
mzur Jul 5, 2024
19d96f8
Make video annotation rendering more efficient
mzur Jul 5, 2024
01b4b83
Make annotation selection more efficient
mzur Jul 8, 2024
9adae2e
Merge branch 'master' into ol-v9
mzur Jul 8, 2024
ed17071
Enable Ellipse and Rectangle tools again with @biigle/ol:9.2.4
mzur Jul 10, 2024
aa347d5
Remove CancelableMap
mzur Jul 10, 2024
a4d47e3
Refactor MagicWandInteraction
mzur Jul 10, 2024
b93db49
Fix behavior of polygon brush and modify tools
mzur Jul 11, 2024
1a7a8ce
Fix issues with polygon brush eraser tool
mzur Jul 11, 2024
5f23767
Refactor polygon brush and modify interactions
mzur Jul 11, 2024
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
929 changes: 294 additions & 635 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
"vue-template-compiler": "^2.6.11"
},
"dependencies": {
"@biigle/ol": "^5.3.0",
"@biigle/ol": "^9.2.4",
"@fortawesome/fontawesome-free": "^5.2.0",
"@turf/boolean-contains": "^6.5.0",
"@turf/difference": "^6.5.0",
"@turf/helpers": "^6.5.0",
"@turf/union": "^6.5.0",
"bootstrap-sass": "^3.3.7",
"echarts": "^5.3.2",
"jsts": "^2.11.0",
Expand Down
5 changes: 2 additions & 3 deletions resources/assets/js/annotations/annotatorContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -501,10 +501,9 @@ export default {
}, 10000);
},
updateColorAdjustment(params) {
let canvas = this.$refs.canvas;
debounce(function () {
debounce(() => {
ImagesStore.updateColorAdjustment(params);
canvas.render();
this.$refs.canvas.fireImageSourceChanged();
}, 100, 'annotations.color-adjustment.update');
},
handleSettingsChange(key, value) {
Expand Down
49 changes: 35 additions & 14 deletions resources/assets/js/annotations/components/annotationCanvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as PolygonValidator from '../ol/PolygonValidator';
import AnnotationTooltip from './annotationCanvas/annotationTooltip';
import AttachLabelInteraction from './annotationCanvas/attachLabelInteraction';
import CanvasSource from '@biigle/ol/source/Canvas';
import CanvasSource from '../ol/source/Canvas';
import Circle from '@biigle/ol/geom/Circle';
import Collection from '@biigle/ol/Collection';
import ControlButton from './controlButton';
Expand Down Expand Up @@ -48,7 +48,6 @@ import {shiftKeyOnly as shiftKeyOnlyCondition} from '@biigle/ol/events/condition
import {singleClick as singleClickCondition} from '@biigle/ol/events/condition';
import { isInvalidShape } from '../utils';


/**
* The annotator canvas
*
Expand Down Expand Up @@ -328,8 +327,6 @@ export default {
center: view.getCenter(),
resolution: view.getResolution(),
});


},
invertPointsYAxis(points) {
// Expects a points array like [x1, y1, x2, y2]. Inverts the y axis of
Expand Down Expand Up @@ -520,7 +517,7 @@ export default {
this.annotationSource.removeFeature(e.feature);
return;
}

if (isInvalidShape(e.feature)) {
// This must be done in the change event handler.
// Not exactly sure why.
Expand Down Expand Up @@ -586,10 +583,10 @@ export default {
this.resetInteractionMode();
}
},
render() {
if (this.map) {
this.map.render();
this.$emit('render');
fireImageSourceChanged() {
const source = this.imageLayer?.getSource();
if (source) {
source.changed();
}
},
handleRegularImage(image) {
Expand Down Expand Up @@ -710,12 +707,34 @@ export default {
this.resetHoveredAnnotations();
},
selectedAnnotations(annotations) {
let source = this.annotationSource;
// This allows selection of annotations outside OpenLayers and forwards
// the state to the SelectInteraction.
let features = this.selectedFeatures;
features.clear();
annotations.forEach(function (annotation) {
features.push(source.getFeatureById(annotation.id));
let featureIdMap = {};
let annotationIdMap = {};
annotations.forEach(a => annotationIdMap[a.id] = true);
let toRemove = [];

features.forEach(f => {
const id = f.getId();
if (annotationIdMap[id]) {
featureIdMap[id] = true;
} else {
toRemove.push(f);
}
});

if (toRemove.length === features.getLength()) {
features.clear();
} else {
toRemove.forEach(f => features.remove(f));
}

annotations
.filter(a => !featureIdMap[a.id])
.forEach(
a => features.push(this.annotationSource.getFeatureById(a.id))
);
},
extent(extent, oldExtent) {
// The extent only truly changes if the width and height changed.
Expand All @@ -736,12 +755,14 @@ export default {
projection: this.projection,
center: center,
resolution: this.resolution,
zoomFactor: 2,
// Allow a maximum of 100x magnification for non-tiled images. More
// cannot be represented in the URL parameters.
minResolution: 0.01,
// Restrict movement.
extent: extent,
showFullExtent: true,
constrainOnlyCenter: true,
padding: [10, 10, 10, 10],
}));

if (this.resolution === undefined) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default {
return layer.get('name') === 'annotations';
},
updateHoveredAnnotations(e) {
let features = this.map.getFeaturesAtPixel(e.pixel, {layerFilter: this.annotationLayerFilter}) || [];
let features = this.map.getFeaturesAtPixel(e.pixel, {layerFilter: this.annotationLayerFilter});
let hash = features.map((f) => f.getId()).join('-');

if (this.hoveredFeaturesHash !== hash) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
import Keyboard from '../../../core/keyboard';
import ModifyPolygonBrushInteraction from '@biigle/ol/interaction/ModifyPolygonBrush';
import PolygonBrushInteraction from '@biigle/ol/interaction/PolygonBrush';
import ModifyPolygonBrushInteraction from '../../ol/interaction/ModifyPolygonBrush';
import PolygonBrushInteraction from '../../ol/interaction/PolygonBrush';
import SelectInteraction from '@biigle/ol/interaction/Select';
import Styles from '../../stores/styles';
import { never, noModifierKeys, click, shiftKeyOnly, altKeyOnly } from '@biigle/ol/events/condition';
Expand Down
70 changes: 47 additions & 23 deletions resources/assets/js/annotations/components/minimap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

<script>
import Feature from '@biigle/ol/Feature';
import {CancelableMap as Map} from '../ol/CancelableMap';
import ImageLayer from '@biigle/ol/layer/Image';
import Map from '@biigle/ol/Map';
import Styles from '../stores/styles';
import TileLayer from '@biigle/ol/layer/Tile';
import VectorLayer from '@biigle/ol/layer/Vector';
import VectorSource from '@biigle/ol/source/Vector';
import View from '@biigle/ol/View';
import ZoomifySource from '@biigle/ol/source/Zoomify';
import {fromExtent} from '@biigle/ol/geom/Polygon';
import {getCenter} from '@biigle/ol/extent';

Expand All @@ -31,10 +34,6 @@ export default {
type: Number,
default: 200,
},
renderActive: {
type: Boolean,
default: true,
},
},
data() {
return {
Expand All @@ -48,7 +47,7 @@ export default {
updateViewport() {
// The map size and center might be undefined if the minimap is created
// initially. This function will be called again once the map is ready.
if (this.mapSize && this.mapView.getCenter()) {
if (this.mapSize && this.mapView.getCenter() && this.mapView.getResolution()) {
this.viewport.setGeometry(fromExtent(this.mapView.calculateExtent(this.mapSize)));
}
},
Expand All @@ -57,6 +56,7 @@ export default {
},
updateMapSize(e) {
this.mapSize = e.target.getSize();
this.updateViewport();
},
updateMapView(e) {
if (this.mapView) {
Expand All @@ -66,6 +66,7 @@ export default {
this.mapView = e.target.getView();
this.mapView.on('change:center', this.updateViewport);
this.mapView.on('change:resolution', this.updateViewport);
this.updateViewport();
},
updateElementSize() {
let imageWidth = this.extent[2];
Expand Down Expand Up @@ -95,37 +96,65 @@ export default {
// to update the layer here, too.
let name = e.element.get('name');
if (name && name.startsWith('image')) {
if (this.originalLayer) {
this.originalLayer.un('change:source', this.handleChangeSource);
}
this.originalLayer = e.element;
if (this.originalLayer instanceof TileLayer) {
this.currentLayer = new TileLayer({
source: this.originalLayer.getSource()
});
} else {
this.currentLayer = new ImageLayer({
source: this.originalLayer.getSource()
});
}
this.originalLayer.on('change:source', this.handleChangeSource);

let layers = this.minimap.getLayers();
if (layers.getLength() > 1) {
layers.setAt(0, e.element);
layers.setAt(0, this.currentLayer);
} else {
layers.insertAt(0, e.element);
layers.insertAt(0, this.currentLayer);
}
}
},
handleChangeSource(e) {
if (this.currentLayer) {
let source = e.target.getSource();

// Create a new tile source instead of sharing it because otherwise the
// minimap would flicker on zoom/pan sometimes.
if (this.currentLayer instanceof TileLayer) {
let image = this.$parent.image
source = new ZoomifySource({
url: image.url,
size: [image.width, image.height],
extent: [0, 0, image.width, image.height],
transition: 0,
});
}

this.currentLayer.setSource(source);
}
},
initImageLayer(layers) {
layers.getArray().forEach((layer) => {
this.refreshImageLayer({element: layer});
});
},
render() {
this.minimap.render();
},
},
watch: {
// Refresh the view if the extent (i.e. image size) changed.
extent() {
this.updateElementSize();
},
renderActive(render) {
if (render) {
this.minimap.render();
} else {
this.minimap.cancelRender();
}
},
},
created() {
// Must not be reactive.
this.originalLayer = null;
this.currentLayer = null;

this.minimap = new Map({
// remove controls
controls: [],
Expand All @@ -145,8 +174,6 @@ export default {
this.updateMapView({target: map});
map.on('change:size', this.updateMapSize);
map.on('change:view', this.updateMapView);
// Initialize the viewport once.
map.once('postcompose', this.updateViewport);

// Add the viewport layer now. Add the image layer later when it was
// added to the map.
Expand All @@ -158,8 +185,6 @@ export default {
this.minimap.on('pointerdrag', this.dragViewport);
this.minimap.on('click', this.dragViewport);
this.initImageLayer(map.getLayers());

this.$parent.$on('render', this.render);
},
mounted() {
this.updateElementSize();
Expand All @@ -175,7 +200,6 @@ export default {
map.un('change:size', this.updateMapSize);
map.un('change:view', this.updateMapView);
map.getLayers().un('add', this.refreshImageLayer);
this.$parent.$off('render', this.render);
},
};
</script>
16 changes: 11 additions & 5 deletions resources/assets/js/annotations/components/screenshotButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,20 @@ export default {
},
capture() {
if (this.map) {
this.map.once('postcompose', (e) => {
this.makeBlob(e.context.canvas)
.then(this.download)
.catch(this.handleError);
});
this.map.once('rendercomplete', this.handleRenderComplete);
this.map.renderSync();
}
},
handleRenderComplete(e) {
// See: https://openlayers.org/en/v6.15.1/examples/export-map.html
// This version is modified/simplified because we want the screenshot
// in the actual device pixel ratio and not at the original size.
const canvas = e.target
.getViewport()
.querySelector('.ol-layer canvas, canvas.ol-layer');

this.makeBlob(canvas).then(this.download).catch(this.handleError);
},
handleError(message) {
Messages.danger(message);
},
Expand Down
13 changes: 0 additions & 13 deletions resources/assets/js/annotations/ol/CancelableMap.js

This file was deleted.

Loading