Skip to content

Commit

Permalink
start working on imageservicelayer function
Browse files Browse the repository at this point in the history
throttle updates on move

try adding initimage
  • Loading branch information
tsutterley committed Mar 18, 2022
1 parent 74e40a3 commit bbc108c
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 58 deletions.
3 changes: 2 additions & 1 deletion examples/CustomProjections.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@
" \"\"\",\n",
" layers=\"MOA_125_HP1_090_230\",\n",
" format='image/png',\n",
" transparent=True,\n",
" transparent=False,\n",
" opacity=0.5,\n",
" url='https://nimbus.cr.usgs.gov/arcgis/services/Antarctica/USGS_EROS_Antarctica_Reference/MapServer/WmsServer',\n",
" crs=MOA3031\n",
")\n",
Expand Down
5 changes: 2 additions & 3 deletions ipyleaflet/leaflet.py
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ class ImageServiceLayer(ImageOverlay):
Attributes
----------
url: string, default ""
Url to the image service.
Url to the image service
f: string, default "image"
response format (use `'image'` to stream as bytes)
format: string, default "png"
Expand Down Expand Up @@ -814,8 +814,7 @@ class ImageServiceLayer(ImageOverlay):
mosaic_rule = Dict({}).tag(sync=True, o=True)
transparent = Bool(False).tag(sync=True, o=True)
crs = Dict(default_value=projections.EPSG3857).tag(sync=True)
_url = Unicode().tag(sync=True)
_bounds = Unicode().tag(sync=True)


class Heatmap(RasterLayer):
"""Heatmap class.
Expand Down
2 changes: 1 addition & 1 deletion js/src/jupyter-leaflet.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ export * from './layers/TileLayer.js';
export * from './layers/VectorTileLayer.js';
export * from './layers/LocalTileLayer.js';
export * from './layers/WMSLayer.js';
export * from './layers/ImageServiceLayer.js';
export * from './layers/MagnifyingGlass.js';
export * from './layers/ImageOverlay.js';
export * from './layers/VideoOverlay.js';
export * from './layers/ImageServiceLayer.js';
export * from './layers/Velocity.js';
export * from './layers/Heatmap.js';
export * from './layers/VectorLayer.js';
Expand Down
66 changes: 13 additions & 53 deletions js/src/layers/ImageServiceLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

const L = require('../leaflet.js');
const imageoverlay = require('./ImageOverlay.js');
const proj = require('../projections.js');

export class LeafletImageServiceLayerModel extends imageoverlay.LeafletImageOverlayModel {
defaults() {
return {
...super.defaults(),
_view_name: 'LeafletImageServiceLayerView',
_model_name: 'LeafletImageServiceLayerModel',
// image server url
url: '',
// response format
f: 'image',
Expand All @@ -19,83 +19,43 @@ export class LeafletImageServiceLayerModel extends imageoverlay.LeafletImageOver
// data type of the raster image
pixel_type: 'F32',
// pixel value or list of pixel values representing no data
no_data: null,
no_data: [],
// how to interpret no data values
no_data_interpretation: '',
// resampling process for interpolating the pixel values
interpolation: '',
// lossy quality for image compression
compression_quality: '',
// order of bands to export for multiple band images
band_ids: null,
band_ids: [],
// time instance or extent for image
time: null,
time: [],
// rules for rendering
rendering_rule: null,
rendering_rule: {},
// rules for mosaicking
mosaic_rule: null,
mosaic_rule: {},
// image transparency
transparent: false,
// coordinate reference system
crs: null,
_url: '',
_bounds: null,
crs: null
};
}
}

export class LeafletImageServiceLayerView extends imageoverlay.LeafletImageOverlayView {
create_obj() {
this.model._url = this.model.get('url') + '/exportImage' + this.buildParams()
this.model._bounds = this._map.getBounds()
this.obj = L.ImageOverlay(this.model._url, this.model._bounds)
this.obj = L.imageServiceLayer(
this.get_options()
)
}

model_events() {
super.model_events();
for (var option in this.get_options()) {
this._map.on('change:' + option, () => {
this.model._url = this.model.get('url') + '/exportImage' + this.buildParams()
this.model._bounds = this._map.getBounds()
this.refresh();
this.model.on('change:' + option, () => {
this.obj.updateUrl();
this.obj.refresh()
});
}
}

model_epsg() {
// get the EPSG code of the current map
var crs = proj.getProjection(this.model.get('crs'))
var spatial_reference = parseInt(crs.code.split(':')[1], 10);
return spatial_reference
}

buildParams () {
// parameters for image server query
var params = {
bbox: this._map.getBounds(),
size: this._map.getSize(),
bboxSR: 4326,
imageSR: this.model_epsg(),
...this.get_options()
};
// merge list parameters
if (params['noData']) {
params['noData'] = params['noData'].join(',');
}
if (params['bandIds']) {
params['bandIds'] = params['bandIds'].join(',');
}
if (params['time']) {
params['time'] = params['time'].join(',');
}
// convert dictionary parameters to JSON
if (params['renderingRule']) {
params['renderingRule'] = JSON.stringify(params['renderingRule']);
}
if (params['mosaicRule']) {
params['mosaicRule'] = JSON.stringify(params['mosaicRule']);
}
// return the formatted query string
return L.Util.getParamString(params);
}
}
172 changes: 172 additions & 0 deletions js/src/leaflet-imageservice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
const proj = require('./projections.js');

L.ImageServiceLayer = L.ImageOverlay.extend({
options: {
// image server url
url: '',
// response format
f: 'image',
// output image format
format: 'png',
// data type of the raster image
pixel_type: 'F32',
// pixel value or list of pixel values representing no data
no_data: [],
// how to interpret no data values
no_data_interpretation: '',
// resampling process for interpolating the pixel values
interpolation: '',
// lossy quality for image compression
compression_quality: '',
// order of bands to export for multiple band images
band_ids: [],
// time instance or extent for image
time: [],
// rules for rendering
rendering_rule: {},
// rules for mosaicking
mosaic_rule: {},
// image transparency
transparent: false,
// coordinate reference system
crs: null,
// update interval for panning
updateInterval: 200
},

initialize: function(options) {
this._url = this.get('url') + '/exportImage' + _buildParams();
this._bounds = this._getBounds();
L.Util.setOptions(this, options);
L.ImageOverlay.prototype.initialize.call(this._url, this._bounds);
},

updateUrl: function() {
this._url = this.get('url') + '/exportImage' + _buildParams();
this._bounds = this._getBounds();
L.ImageOverlay.prototype.setUrl.call(this._url);
L.ImageOverlay.prototype.setBounds.call(this._bounds);
},

onAdd: function (map) {
this._map = map;
this.updateUrl();
if (!this._image) {
this._initImage();
}
this._map.on('moveend', () => {
L.Util.throttle(this.updateUrl(),this.options.updateInterval,this);
L.ImageOverlay.prototype._reset.call(this);
});
L.ImageOverlay.prototype.onAdd.call(this);
},

onRemove: function (map) {
L.ImageOverlay.prototype.onRemove.call(this, map);
},

bringToFront: function () {
L.ImageOverlay.prototype.bringToFront.call(this);
return this;
},

bringToBack: function () {
L.ImageOverlay.prototype.bringToBack.call(this);
return this;
},

setUrl: function (url) {
this._url = url;
L.ImageOverlay.prototype.setUrl.call(this._url);
return this;
},

setBounds: function (bounds) {
this._bounds = bounds;
L.ImageOverlay.prototype.setBounds.call(this._bounds);
return this;
},

getBounds: function () {
return this._bounds;
},

_getBBox: function() {
// get the bounding box of the current map formatted for exportImage
var pixelbounds = this._map.getPixelBounds();
var sw = map.unproject(pixelbounds.getBottomLeft());
var ne = map.unproject(pixelbounds.getTopRight());
return [this._map.options.crs.project(ne),this._map.options.crs.project(sw)];
},

_getBounds: function() {
// get the bounds of the current map for the ImageOverlay
return [[this._map.getBounds().getSouth(),this._map.getBounds().getWest()],
[this._map.getBounds().getNorth(),this._map.getBounds().getEast()]];
},

_getSize: function() {
// get the size of the current map
var size = this._map.getSize();
return [size.x, size.y];
},

_getEPSG: function() {
// get the EPSG code of the current map
var crs = proj.getProjection(this.model.get('crs'));
var spatial_reference = parseInt(crs.code.split(':')[1], 10);
return spatial_reference;
},

_buildParams: function() {
// parameters for image server query
var params = {
bbox: this._getBBox(),
size: this._getSize(),
bboxSR: this._getEPSG(),
imageSR: this._getEPSG(),
...this.get_options()
};
// merge list parameters
if (params['noData']) {
params['noData'] = params['noData'].join(',');
}
if (params['bandIds']) {
params['bandIds'] = params['bandIds'].join(',');
}
if (params['time']) {
params['time'] = params['time'].join(',');
}
// convert dictionary parameters to JSON
if (params['renderingRule']) {
params['renderingRule'] = JSON.stringify(params['renderingRule']);
}
if (params['mosaicRule']) {
params['mosaicRule'] = JSON.stringify(params['mosaicRule']);
}
// return the formatted query string
return L.Util.getParamString(params);
},

_initImage: function () {
var img = this._image = L.DomUtil.create('img');
L.DomUtil.addClass(img, 'leaflet-image-layer');
if (this._zoomAnimated) { L.DomUtil.addClass(img, 'leaflet-zoom-animated'); }
img.onselectstart = L.Util.falseFn;
img.onmousemove = L.Util.falseFn;
img.onload = L.Util.bind(this.fire, this, 'load');
img.src = this._url;
img.alt = this.options.alt;
},

_reset: function () {
L.ImageOverlay.prototype._reset.call(this);
},

});

L.imageServiceLayer = function (options) {
return new L.ImageServiceLayer(options);
};
1 change: 1 addition & 0 deletions js/src/leaflet.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require('leaflet.markercluster');
require('leaflet-velocity');
require('leaflet-measure');
require('./leaflet-heat.js');
require('./leaflet-imageservice.js');
require('./leaflet-magnifyingglass.js');
require('leaflet-rotatedmarker');
require('leaflet-fullscreen');
Expand Down

0 comments on commit bbc108c

Please sign in to comment.