Skip to content

Commit 0538bcb

Browse files
committed
update way to apply mask
1 parent f2e2090 commit 0538bcb

File tree

4 files changed

+69
-27
lines changed

4 files changed

+69
-27
lines changed

demos/schm/demo.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ const densifier = new UnsnappedDensifier({ });
5555
return doubleClick(mapBrowserEvent) && pointType !== 'POI';
5656
};
5757

58+
const search = new URLSearchParams(document.location.search);
59+
60+
const showMask = search.get('drawMask') === 'true';
61+
5862
const trackManager = new TrackManager({
5963
map: map,
6064
router: router,
@@ -68,9 +72,10 @@ const densifier = new UnsnappedDensifier({ });
6872
addLastPointCondition: singleClick, // we have to use single click otherwise the double click is not fired
6973
addControlPointCondition: doubleClick,
7074
hitTolerance: 15,
75+
drawExtent: showMask ? [2443048, 1030343, 2894802, 1339995] : undefined,
76+
drawMaskColor: showMask ? 'rgba(255, 0, 0, 0.3)' : undefined,
7177
});
7278

73-
const search = new URLSearchParams(document.location.search);
7479
const trackId = search.get('trackId');
7580
if (trackId) {
7681
trackManager.restoreFeatures([
@@ -83,6 +88,9 @@ const densifier = new UnsnappedDensifier({ });
8388
}
8489

8590
trackManager.mode = 'edit';
91+
document.getElementById('edit-mode-switch').addEventListener('click', () => {
92+
trackManager.mode = trackManager.mode === 'edit' ? '' : 'edit';
93+
})
8694
}
8795

8896
main();

demos/schm/schm.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,16 @@
3030
-webkit-user-select: none;
3131
-moz-user-select: none;
3232
}
33+
#edit-mode-switch {
34+
position: absolute;
35+
top: 10px;
36+
right: 10px;
37+
}
3338
</style>
3439
</head>
3540

3641
<body>
3742
<div id="map"></div>
43+
<button id="edit-mode-switch">Switch edit mode</button>
3844
</body>
3945
</html>

demos/schm/swisstopo.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export function createMap(target) {
3737
extent: extent,
3838
center: [2532661.0, 1151654.0],
3939
zoom: 10,
40+
constrainOnlyCenter: true,
4041
});
4142

4243
const bgLayer = createSwisstopoLayer('ch.swisstopo.pixelkarte-farbe');

src/interaction/TrackManager.ts

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ import type {Coordinate} from 'ol/coordinate';
2424
import type {FeatureType} from './TrackData';
2525
import type {Snapper} from 'src/snapper';
2626
import { Densifier } from 'src/densifier';
27-
import {fromExtent} from "ol/geom/Polygon";
2827
import {Extent} from "ol/extent";
29-
import {EXTENT as epsg3857Extent} from "ol/proj/epsg3857";
30-
import {EXTENT as epsg4326Extent} from "ol/proj/epsg4326";
28+
import {EventsKey} from 'ol/events';
29+
import RenderEvent from "ol/render/Event";
30+
import {unByKey} from "ol/Observable";
3131

3232
export type TrackMode = 'edit' | '';
3333
export type TrackSubMode = 'addpoi' | 'editpoi' | '';
@@ -78,14 +78,16 @@ export interface Options {
7878
* Pixel tolerance for considering the pointer close enough to a segment for snapping.
7979
*/
8080
hitTolerance: number;
81+
8182
/**
82-
* Optional layer to display a drawing area mask. drawExtent should be specified to use mask.
83+
* Drawing area extent.
8384
*/
84-
drawMaskLayer?: VectorLayer<VectorSource>;
85+
drawExtent?: Extent;
86+
8587
/**
86-
* Drawing area extent. drawMaskLayer should be specified.
88+
* Drawing mask color. CSS string
8789
*/
88-
drawExtent?: Extent;
90+
drawMaskColor?: string;
8991
}
9092

9193

@@ -127,7 +129,9 @@ export default class TrackManager<POIMeta> {
127129
private interaction_: TrackInteraction;
128130
private historyManager_ = new HistoryManager<Feature<Point|LineString>[]>();
129131

130-
private drawMaskLayer: VectorLayer<VectorSource>;
132+
private drawExtent_: Extent | undefined;
133+
private drawMaskColor_: string = 'rgba(241, 245, 249, 1)';
134+
private addDrawingMaskKey_: EventsKey | undefined;
131135

132136
constructor(options: Options) {
133137
this.map_ = options.map;
@@ -148,10 +152,9 @@ export default class TrackManager<POIMeta> {
148152
trackData: this.trackData_
149153
});
150154

151-
this.drawMaskLayer = options.drawMaskLayer;
152-
if (options.drawExtent && this.drawMaskLayer) {
153-
this.drawMaskLayer.getSource().addFeature(this.calculateMaskFeature(options.drawExtent))
154-
this.drawMaskLayer.setVisible(false)
155+
this.drawExtent_ = options.drawExtent;
156+
if (options.drawMaskColor) {
157+
this.drawMaskColor_ = options.drawMaskColor;
155158
}
156159

157160
this.interaction_ = new TrackInteraction({
@@ -352,6 +355,10 @@ export default class TrackManager<POIMeta> {
352355
this.map_.once("postrender", () => {
353356
this.interaction_.addMapInOutEventListeners(this.map_.getViewport());
354357
});
358+
359+
if (this.drawExtent_) {
360+
this.addDrawingMaskKey_ = this.map_.on('postcompose', (evt) => this.addDrawingMask(evt, this.drawExtent_));
361+
}
355362
} else {
356363
this.historyManager_.clear();
357364
if (this.shadowTrackLayer_) {
@@ -360,8 +367,11 @@ export default class TrackManager<POIMeta> {
360367
if (this.map_?.getViewport()) {
361368
this.interaction_.removeMapInOutEventListeners(this.map_.getViewport());
362369
}
370+
if (this.addDrawingMaskKey_) {
371+
unByKey(this.addDrawingMaskKey_);
372+
this.addDrawingMaskKey_ = undefined;
373+
}
363374
}
364-
this.drawMaskLayer?.setVisible(edit);
365375
this.interaction_.setActive(edit);
366376
this.mode_ = mode || '';
367377
this.render();
@@ -637,18 +647,35 @@ export default class TrackManager<POIMeta> {
637647
this.shadowTrackLayer_.getSource().changed();
638648
}
639649

640-
private calculateMaskFeature(extent: Extent) {
641-
const projection = this.map_.getView().getProjection();
642-
// for some projections (like EPSG:2056) extent smaller than visible map
643-
let wExtent = projection.getExtent();
644-
if (projection.getUnits() === 'm') {
645-
wExtent = epsg3857Extent;
646-
} else if (projection.getUnits() === 'degrees') {
647-
wExtent = epsg4326Extent;
648-
}
649-
const mask = fromExtent(wExtent);
650-
const drawingArea = fromExtent(extent);
651-
mask.appendLinearRing(drawingArea.getLinearRing(0));
652-
return new Feature(mask);
650+
addDrawingMask(event: RenderEvent, extent: Extent) {
651+
if (!extent?.length) return;
652+
const viewport = event.target.getViewport();
653+
const canvases = viewport.getElementsByTagName('canvas');
654+
const canvas = canvases.item(canvases.length - 1);
655+
const context = canvas.getContext('2d');
656+
657+
const coordinates = [
658+
[extent[0], extent[1]], // Bottom-left
659+
[extent[0], extent[3]], // Top-left
660+
[extent[2], extent[3]], // Top-right
661+
[extent[2], extent[1]], // Bottom-right
662+
];
663+
664+
const pixelCoordinates = coordinates.map((coord) => this.map_.getPixelFromCoordinate(coord));
665+
666+
context.beginPath();
667+
668+
// outer rectangle
669+
context.rect(0, 0, canvas.width, canvas.height);
670+
671+
const width = pixelCoordinates[3][0] - pixelCoordinates[0][0];
672+
const height = pixelCoordinates[1][1] - pixelCoordinates[0][1];
673+
674+
// inner rectangle
675+
context.rect(pixelCoordinates[0][0], pixelCoordinates[0][1], width, height);
676+
677+
context.closePath();
678+
context.fillStyle = this.drawMaskColor_;
679+
context.fill('evenodd');
653680
}
654681
}

0 commit comments

Comments
 (0)