Merge branch 'master' into patch-4
This commit is contained in:
@@ -275,7 +275,9 @@ class MapBrowserEventHandler extends EventTarget {
|
||||
* @private
|
||||
*/
|
||||
handleTouchMove_(event) {
|
||||
if (this.originalPointerMoveEvent_.defaultPrevented) {
|
||||
// Due to https://github.com/mpizenberg/elm-pep/issues/2, `this.originalPointerMoveEvent_`
|
||||
// may not be initialized yet when we get here on a platform without native pointer events.
|
||||
if (!this.originalPointerMoveEvent_ || this.originalPointerMoveEvent_.defaultPrevented) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class Observable extends EventTarget {
|
||||
/**
|
||||
* Listen for a certain type of event.
|
||||
* @param {string|Array<string>} type The event type or array of event types.
|
||||
* @param {function(?): ?} listener The listener function.
|
||||
* @param {import("./events.js").ListenerFunction} listener The listener function.
|
||||
* @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Unique key for the listener. If
|
||||
* called with an array of event types as the first argument, the return
|
||||
* will be an array of keys.
|
||||
|
||||
@@ -405,7 +405,6 @@ class View extends BaseObject {
|
||||
} else if (options.zoom !== undefined) {
|
||||
this.setZoom(options.zoom);
|
||||
}
|
||||
this.resolveConstraints(0);
|
||||
|
||||
this.setProperties(properties);
|
||||
|
||||
@@ -609,10 +608,15 @@ class View extends BaseObject {
|
||||
if (series[0].callback) {
|
||||
animationCallback(series[0].callback, false);
|
||||
}
|
||||
anchor = anchor ||
|
||||
series.filter(function(animation) {
|
||||
return !animation.complete;
|
||||
})[0].anchor;
|
||||
if (!anchor) {
|
||||
for (let j = 0, jj = series.length; j < jj; ++j) {
|
||||
const animation = series[j];
|
||||
if (!animation.complete) {
|
||||
anchor = animation.anchor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.animations_.length = 0;
|
||||
this.cancelAnchor_ = anchor;
|
||||
@@ -762,6 +766,7 @@ class View extends BaseObject {
|
||||
*/
|
||||
setViewportSize(opt_size) {
|
||||
this.viewportSize_ = Array.isArray(opt_size) ? opt_size.slice() : [100, 100];
|
||||
this.resolveConstraints(0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,6 @@ import {clear} from './obj.js';
|
||||
* @api
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Listener function. This function is called with an event object as argument.
|
||||
* When the function returns `false`, event propagation will stop.
|
||||
@@ -22,6 +21,14 @@ import {clear} from './obj.js';
|
||||
* @api
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ListenerObject
|
||||
* @property {ListenerFunction} handleEvent
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {ListenerFunction|ListenerObject} Listener
|
||||
*/
|
||||
|
||||
/**
|
||||
* Registers an event listener on an event target. Inspired by
|
||||
|
||||
@@ -56,7 +56,7 @@ class Target extends Disposable {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object<string, Array<import("../events.js").ListenerFunction>>}
|
||||
* @type {!Object<string, Array<import("../events.js").Listener>>}
|
||||
*/
|
||||
this.listeners_ = {};
|
||||
|
||||
@@ -64,7 +64,7 @@ class Target extends Disposable {
|
||||
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {import("../events.js").ListenerFunction} listener Listener.
|
||||
* @param {import("../events.js").Listener} listener Listener.
|
||||
*/
|
||||
addEventListener(type, listener) {
|
||||
if (!type || !listener) {
|
||||
@@ -85,15 +85,13 @@ class Target extends Disposable {
|
||||
* of this type. The event parameter can either be a string or an
|
||||
* Object with a `type` property.
|
||||
*
|
||||
* @param {{type: string,
|
||||
* target: (EventTargetLike|undefined),
|
||||
* propagationStopped: (boolean|undefined)}|
|
||||
* import("./Event.js").default|string} event Event object.
|
||||
* @param {import("./Event.js").default|string} event Event object.
|
||||
* @return {boolean|undefined} `false` if anyone called preventDefault on the
|
||||
* event object or if any of the listeners returned false.
|
||||
* @api
|
||||
*/
|
||||
dispatchEvent(event) {
|
||||
/** @type {import("./Event.js").default|Event} */
|
||||
const evt = typeof event === 'string' ? new Event(event) : event;
|
||||
const type = evt.type;
|
||||
if (!evt.target) {
|
||||
@@ -108,7 +106,12 @@ class Target extends Disposable {
|
||||
}
|
||||
++this.dispatching_[type];
|
||||
for (let i = 0, ii = listeners.length; i < ii; ++i) {
|
||||
if (listeners[i].call(this, evt) === false || evt.propagationStopped) {
|
||||
if ('handleEvent' in listeners[i]) {
|
||||
propagate = /** @type {import("../events.js").ListenerObject} */ (listeners[i]).handleEvent(evt);
|
||||
} else {
|
||||
propagate = /** @type {import("../events.js").ListenerFunction} */ (listeners[i]).call(this, evt);
|
||||
}
|
||||
if (propagate === false || evt.propagationStopped) {
|
||||
propagate = false;
|
||||
break;
|
||||
}
|
||||
@@ -138,7 +141,7 @@ class Target extends Disposable {
|
||||
* order that they will be called in.
|
||||
*
|
||||
* @param {string} type Type.
|
||||
* @return {Array<import("../events.js").ListenerFunction>} Listeners.
|
||||
* @return {Array<import("../events.js").Listener>} Listeners.
|
||||
*/
|
||||
getListeners(type) {
|
||||
return this.listeners_[type];
|
||||
@@ -157,7 +160,7 @@ class Target extends Disposable {
|
||||
|
||||
/**
|
||||
* @param {string} type Type.
|
||||
* @param {import("../events.js").ListenerFunction} listener Listener.
|
||||
* @param {import("../events.js").Listener} listener Listener.
|
||||
*/
|
||||
removeEventListener(type, listener) {
|
||||
const listeners = this.listeners_[type];
|
||||
|
||||
@@ -778,18 +778,38 @@ export function intersectsSegment(extent, start, end) {
|
||||
* @param {import("./proj.js").TransformFunction} transformFn Transform function.
|
||||
* Called with `[minX, minY, maxX, maxY]` extent coordinates.
|
||||
* @param {Extent=} opt_extent Destination extent.
|
||||
* @param {number=} opt_stops Number of stops per side used for the transform.
|
||||
* By default only the corners are used.
|
||||
* @return {Extent} Extent.
|
||||
* @api
|
||||
*/
|
||||
export function applyTransform(extent, transformFn, opt_extent) {
|
||||
const coordinates = [
|
||||
extent[0], extent[1],
|
||||
extent[0], extent[3],
|
||||
extent[2], extent[1],
|
||||
extent[2], extent[3]
|
||||
];
|
||||
export function applyTransform(extent, transformFn, opt_extent, opt_stops) {
|
||||
let coordinates = [];
|
||||
if (opt_stops > 1) {
|
||||
const width = extent[2] - extent[0];
|
||||
const height = extent[3] - extent[1];
|
||||
for (let i = 0; i < opt_stops; ++i) {
|
||||
coordinates.push(
|
||||
extent[0] + width * i / opt_stops, extent[1],
|
||||
extent[2], extent[1] + height * i / opt_stops,
|
||||
extent[2] - width * i / opt_stops, extent[3],
|
||||
extent[0], extent[3] - height * i / opt_stops
|
||||
);
|
||||
}
|
||||
} else {
|
||||
coordinates = [
|
||||
extent[0], extent[1],
|
||||
extent[2], extent[1],
|
||||
extent[2], extent[3],
|
||||
extent[0], extent[3]
|
||||
];
|
||||
}
|
||||
transformFn(coordinates, coordinates, 2);
|
||||
const xs = [coordinates[0], coordinates[2], coordinates[4], coordinates[6]];
|
||||
const ys = [coordinates[1], coordinates[3], coordinates[5], coordinates[7]];
|
||||
const xs = [];
|
||||
const ys = [];
|
||||
for (let i = 0, l = coordinates.length; i < l; i += 2) {
|
||||
xs.push(coordinates[i]);
|
||||
ys.push(coordinates[i + 1]);
|
||||
}
|
||||
return _boundingExtentXYs(xs, ys, opt_extent);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ import {fromUserCoordinate, getUserProjection} from '../proj.js';
|
||||
* geometry is the geometry that is returned when the function is called without
|
||||
* a second argument.
|
||||
* @typedef {function(!SketchCoordType, import("../geom/SimpleGeometry.js").default=,
|
||||
* import("../proj/Projection.js").default):
|
||||
* import("../proj/Projection.js").default=):
|
||||
* import("../geom/SimpleGeometry.js").default} GeometryFunction
|
||||
*/
|
||||
|
||||
|
||||
@@ -12,10 +12,19 @@ import VectorSource from '../source/Vector.js';
|
||||
import {
|
||||
equivalent as equivalentProjection,
|
||||
get as getProjection,
|
||||
getTransform,
|
||||
transformExtent
|
||||
getTransform
|
||||
} from '../proj.js';
|
||||
import {getCenter, getHeight, getWidth, intersects, equals, getIntersection, isEmpty} from '../extent.js';
|
||||
import {
|
||||
applyTransform,
|
||||
containsCoordinate,
|
||||
equals,
|
||||
getCenter,
|
||||
getHeight,
|
||||
getIntersection,
|
||||
getWidth,
|
||||
intersects,
|
||||
isEmpty
|
||||
} from '../extent.js';
|
||||
import {clamp} from '../math.js';
|
||||
import Style from '../style/Style.js';
|
||||
import Feature from '../Feature.js';
|
||||
@@ -144,7 +153,8 @@ const INTERVALS = [
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Layer that renders a grid for a coordinate system.
|
||||
* Layer that renders a grid for a coordinate system (currently only EPSG:4326 is supported).
|
||||
* Note that the view projection must define both extent and worldExtent.
|
||||
*
|
||||
* @fires import("../render/Event.js").RenderEvent
|
||||
* @api
|
||||
@@ -208,25 +218,25 @@ class Graticule extends VectorLayer {
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.maxLatP_ = Infinity;
|
||||
this.maxX_ = Infinity;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.maxLonP_ = Infinity;
|
||||
this.maxY_ = Infinity;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.minLatP_ = -Infinity;
|
||||
this.minX_ = -Infinity;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.minLonP_ = -Infinity;
|
||||
this.minY_ = -Infinity;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
@@ -276,6 +286,30 @@ class Graticule extends VectorLayer {
|
||||
*/
|
||||
this.projectionCenterLonLat_ = null;
|
||||
|
||||
/**
|
||||
* @type {import("../coordinate.js").Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.bottomLeft_ = null;
|
||||
|
||||
/**
|
||||
* @type {import("../coordinate.js").Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.bottomRight_ = null;
|
||||
|
||||
/**
|
||||
* @type {import("../coordinate.js").Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.topLeft_ = null;
|
||||
|
||||
/**
|
||||
* @type {import("../coordinate.js").Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.topRight_ = null;
|
||||
|
||||
/**
|
||||
* @type {Array<GraticuleLabelDataType>}
|
||||
* @private
|
||||
@@ -664,24 +698,67 @@ class Graticule extends VectorLayer {
|
||||
return;
|
||||
}
|
||||
|
||||
const centerLonLat = this.toLonLatTransform_(center);
|
||||
let centerLon = centerLonLat[0];
|
||||
let centerLat = centerLonLat[1];
|
||||
// Constrain the center to fit into the extent available to the graticule
|
||||
|
||||
const validCenterP = [
|
||||
clamp(center[0], this.minX_, this.maxX_),
|
||||
clamp(center[1], this.minY_, this.maxY_)
|
||||
];
|
||||
|
||||
// Transform the center to lon lat
|
||||
// Some projections may have a void area at the poles
|
||||
// so replace any NaN latitudes with the min or max value closest to a pole
|
||||
|
||||
const centerLonLat = this.toLonLatTransform_(validCenterP);
|
||||
if (isNaN(centerLonLat[1])) {
|
||||
centerLonLat[1] = Math.abs(this.maxLat_) >= Math.abs(this.minLat_) ?
|
||||
this.maxLat_ : this.minLat_;
|
||||
}
|
||||
let centerLon = clamp(centerLonLat[0], this.minLon_, this.maxLon_);
|
||||
let centerLat = clamp(centerLonLat[1], this.minLat_, this.maxLat_);
|
||||
const maxLines = this.maxLines_;
|
||||
let cnt, idx, lat, lon;
|
||||
|
||||
let validExtent = [
|
||||
Math.max(extent[0], this.minLonP_),
|
||||
Math.max(extent[1], this.minLatP_),
|
||||
Math.min(extent[2], this.maxLonP_),
|
||||
Math.min(extent[3], this.maxLatP_)
|
||||
// Limit the extent to fit into the extent available to the graticule
|
||||
|
||||
const validExtentP = [
|
||||
clamp(extent[0], this.minX_, this.maxX_),
|
||||
clamp(extent[1], this.minY_, this.maxY_),
|
||||
clamp(extent[2], this.minX_, this.maxX_),
|
||||
clamp(extent[3], this.minY_, this.maxY_)
|
||||
];
|
||||
|
||||
validExtent = transformExtent(validExtent, this.projection_, 'EPSG:4326');
|
||||
const maxLat = validExtent[3];
|
||||
const maxLon = validExtent[2];
|
||||
const minLat = validExtent[1];
|
||||
const minLon = validExtent[0];
|
||||
// Transform the extent to get the lon lat ranges for the edges of the extent
|
||||
|
||||
const validExtent = applyTransform(validExtentP, this.toLonLatTransform_, undefined, 8);
|
||||
|
||||
// Check if extremities of the world extent lie inside the extent
|
||||
// (for example the pole in a polar projection)
|
||||
// and extend the extent as appropriate
|
||||
|
||||
if (containsCoordinate(validExtentP, this.bottomLeft_)) {
|
||||
validExtent[0] = this.minLon_;
|
||||
validExtent[1] = this.minLat_;
|
||||
}
|
||||
if (containsCoordinate(validExtentP, this.bottomRight_)) {
|
||||
validExtent[2] = this.maxLon_;
|
||||
validExtent[1] = this.minLat_;
|
||||
}
|
||||
if (containsCoordinate(validExtentP, this.topLeft_)) {
|
||||
validExtent[0] = this.minLon_;
|
||||
validExtent[3] = this.maxLat_;
|
||||
}
|
||||
if (containsCoordinate(validExtentP, this.topRight_)) {
|
||||
validExtent[2] = this.maxLon_;
|
||||
validExtent[3] = this.maxLat_;
|
||||
}
|
||||
|
||||
// The transformed center may also extend the lon lat ranges used for rendering
|
||||
|
||||
const maxLat = clamp(validExtent[3], centerLat, this.maxLat_);
|
||||
const maxLon = clamp(validExtent[2], centerLon, this.maxLon_);
|
||||
const minLat = clamp(validExtent[1], this.minLat_, centerLat);
|
||||
const minLon = clamp(validExtent[0], this.minLon_, centerLon);
|
||||
|
||||
// Create meridians
|
||||
|
||||
@@ -752,11 +829,13 @@ class Graticule extends VectorLayer {
|
||||
/** @type {Array<number>} **/
|
||||
const p2 = [];
|
||||
for (let i = 0, ii = this.intervals_.length; i < ii; ++i) {
|
||||
const delta = this.intervals_[i] / 2;
|
||||
const delta = clamp(this.intervals_[i] / 2, 0, 90);
|
||||
// Don't attempt to transform latitudes beyond the poles!
|
||||
const clampedLat = clamp(centerLat, -90 + delta, 90 - delta);
|
||||
p1[0] = centerLon - delta;
|
||||
p1[1] = centerLat - delta;
|
||||
p1[1] = clampedLat - delta;
|
||||
p2[0] = centerLon + delta;
|
||||
p2[1] = centerLat + delta;
|
||||
p2[1] = clampedLat + delta;
|
||||
this.fromLonLatTransform_(p1, p1);
|
||||
this.fromLonLatTransform_(p2, p2);
|
||||
const dist = Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2);
|
||||
@@ -896,23 +975,66 @@ class Graticule extends VectorLayer {
|
||||
const epsg4326Projection = getProjection('EPSG:4326');
|
||||
|
||||
const worldExtent = projection.getWorldExtent();
|
||||
const worldExtentP = transformExtent(worldExtent, epsg4326Projection, projection);
|
||||
|
||||
this.maxLat_ = worldExtent[3];
|
||||
this.maxLon_ = worldExtent[2];
|
||||
this.minLat_ = worldExtent[1];
|
||||
this.minLon_ = worldExtent[0];
|
||||
|
||||
this.maxLatP_ = worldExtentP[3];
|
||||
this.maxLonP_ = worldExtentP[2];
|
||||
this.minLatP_ = worldExtentP[1];
|
||||
this.minLonP_ = worldExtentP[0];
|
||||
// If the world extent crosses the dateline define a custom transform to
|
||||
// return longitudes which wrap the dateline
|
||||
|
||||
const toLonLatTransform = getTransform(projection, epsg4326Projection);
|
||||
if (this.minLon_ < this.maxLon_) {
|
||||
this.toLonLatTransform_ = toLonLatTransform;
|
||||
} else {
|
||||
const split = this.minLon_ + this.maxLon_ / 2;
|
||||
this.maxLon_ += 360;
|
||||
this.toLonLatTransform_ = function(coordinates, opt_output, opt_dimension) {
|
||||
const dimension = opt_dimension || 2;
|
||||
const lonLatCoordinates = toLonLatTransform(coordinates, opt_output, dimension);
|
||||
for (let i = 0, l = lonLatCoordinates.length; i < l; i += dimension) {
|
||||
if (lonLatCoordinates[i] < split) {
|
||||
lonLatCoordinates[i] += 360;
|
||||
}
|
||||
}
|
||||
return lonLatCoordinates;
|
||||
};
|
||||
}
|
||||
|
||||
// Transform the extent to get the limits of the view projection extent
|
||||
// which should be available to the graticule
|
||||
|
||||
this.fromLonLatTransform_ = getTransform(epsg4326Projection, projection);
|
||||
const worldExtentP = applyTransform(
|
||||
[this.minLon_, this.minLat_, this.maxLon_, this.maxLat_],
|
||||
this.fromLonLatTransform_,
|
||||
undefined,
|
||||
8
|
||||
);
|
||||
|
||||
this.toLonLatTransform_ = getTransform(projection, epsg4326Projection);
|
||||
this.minX_ = worldExtentP[0];
|
||||
this.maxX_ = worldExtentP[2];
|
||||
this.minY_ = worldExtentP[1];
|
||||
this.maxY_ = worldExtentP[3];
|
||||
|
||||
// Determine the view projection coordinates of the extremities of the world extent
|
||||
// as these may lie inside a view extent (for example the pole in a polar projection)
|
||||
|
||||
this.bottomLeft_ = this.fromLonLatTransform_([this.minLon_, this.minLat_]);
|
||||
this.bottomRight_ = this.fromLonLatTransform_([this.maxLon_, this.minLat_]);
|
||||
this.topLeft_ = this.fromLonLatTransform_([this.minLon_, this.maxLat_]);
|
||||
this.topRight_ = this.fromLonLatTransform_([this.maxLon_, this.maxLat_]);
|
||||
|
||||
// Transform the projection center to lon lat
|
||||
// Some projections may have a void area at the poles
|
||||
// so replace any NaN latitudes with the min or max value closest to a pole
|
||||
|
||||
this.projectionCenterLonLat_ = this.toLonLatTransform_(getCenter(projection.getExtent()));
|
||||
if (isNaN(this.projectionCenterLonLat_[1])) {
|
||||
this.projectionCenterLonLat_[1] = Math.abs(this.maxLat_) >= Math.abs(this.minLat_) ?
|
||||
this.maxLat_ : this.minLat_;
|
||||
}
|
||||
|
||||
this.projection_ = projection;
|
||||
}
|
||||
|
||||
@@ -476,12 +476,14 @@ export function transform(coordinate, source, destination) {
|
||||
* @param {import("./extent.js").Extent} extent The extent to transform.
|
||||
* @param {ProjectionLike} source Source projection-like.
|
||||
* @param {ProjectionLike} destination Destination projection-like.
|
||||
* @param {number=} opt_stops Number of stops per side used for the transform.
|
||||
* By default only the corners are used.
|
||||
* @return {import("./extent.js").Extent} The transformed extent.
|
||||
* @api
|
||||
*/
|
||||
export function transformExtent(extent, source, destination) {
|
||||
export function transformExtent(extent, source, destination, opt_stops) {
|
||||
const transformFunc = getTransform(source, destination);
|
||||
return applyTransform(extent, transformFunc);
|
||||
return applyTransform(extent, transformFunc, undefined, opt_stops);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -290,7 +290,8 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
this.sourceListenKeys_ = [
|
||||
listen(source, VectorEventType.ADDFEATURE, this.handleSourceFeatureAdded_, this),
|
||||
listen(source, VectorEventType.CHANGEFEATURE, this.handleSourceFeatureChanged_, this),
|
||||
listen(source, VectorEventType.REMOVEFEATURE, this.handleSourceFeatureDelete_, this)
|
||||
listen(source, VectorEventType.REMOVEFEATURE, this.handleSourceFeatureDelete_, this),
|
||||
listen(source, VectorEventType.CLEAR, this.handleSourceFeatureClear_, this)
|
||||
];
|
||||
source.forEachFeature(function(feature) {
|
||||
this.featureCache_[getUid(feature)] = {
|
||||
@@ -339,6 +340,14 @@ class WebGLPointsLayerRenderer extends WebGLLayerRenderer {
|
||||
this.featureCount_--;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleSourceFeatureClear_() {
|
||||
this.featureCache_ = {};
|
||||
this.featureCount_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
@@ -33,7 +33,7 @@ import ImageSource from './Image.js';
|
||||
* the value returned by the function is later changed then
|
||||
* `changed` should be called on the source for the source to
|
||||
* invalidate the current cached image. See: {@link module:ol/Observable~Observable#changed}
|
||||
* @property {import("../proj.js").ProjectionLike} projection Projection.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {number} [ratio=1.5] Ratio. 1 means canvases are the size of the map viewport, 2 means twice the
|
||||
* width and height of the map viewport, and so on. Must be `1` or higher.
|
||||
* @property {Array<number>} [resolutions] Resolutions.
|
||||
|
||||
@@ -20,7 +20,7 @@ import {appendParams} from '../uri.js';
|
||||
* @property {boolean} [hidpi=true] Use the `ol/Map#pixelRatio` value when requesting
|
||||
* the image from the remote server.
|
||||
* @property {boolean} [useOverlay] If `true`, will use `GETDYNAMICMAPOVERLAYIMAGE`.
|
||||
* @property {import("../proj.js").ProjectionLike} projection Projection.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {number} [ratio=1] Ratio. `1` means image requests are the size of the map viewport, `2` means
|
||||
* twice the width and height of the map viewport, and so on. Must be `1` or higher.
|
||||
* @property {Array<number>} [resolutions] Resolutions.
|
||||
|
||||
@@ -19,7 +19,7 @@ import ImageSource, {defaultImageLoadFunction} from './Image.js';
|
||||
* @property {import("../extent.js").Extent} [imageExtent] Extent of the image in map coordinates.
|
||||
* This is the [left, bottom, right, top] map coordinates of your image.
|
||||
* @property {import("../Image.js").LoadFunction} [imageLoadFunction] Optional function to load an image given a URL.
|
||||
* @property {import("../proj.js").ProjectionLike} projection Projection.
|
||||
* @property {import("../proj.js").ProjectionLike} [projection] Projection. Default is the view projection.
|
||||
* @property {import("../size.js").Size} [imageSize] Size of the image in pixels. Usually the image size is auto-detected, so this
|
||||
* only needs to be set if auto-detection fails for some reason.
|
||||
* @property {string} url Image URL.
|
||||
|
||||
@@ -11,6 +11,7 @@ import {createCanvasContext2D} from '../dom.js';
|
||||
import {toSize} from '../size.js';
|
||||
import TileImage from './TileImage.js';
|
||||
import TileGrid from '../tilegrid/TileGrid.js';
|
||||
import {getCenter} from '../extent.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -90,7 +91,7 @@ export class CustomTile extends ImageTile {
|
||||
* Higher values can increase reprojection performance, but decrease precision.
|
||||
* @property {object} [reprojectionContextOptions] Optional properties to set on the canvas context used
|
||||
* for reprojection. For example specify `{imageSmoothingEnabled: false}` to disable image smoothing.
|
||||
* @property {string} [url] URL template or base URL of the Zoomify service.
|
||||
* @property {string} url URL template or base URL of the Zoomify service.
|
||||
* A base URL is the fixed part
|
||||
* of the URL, excluding the tile group, z, x, and y folder structure, e.g.
|
||||
* `http://my.zoomify.info/IMAGE.TIF/`. A URL template must include
|
||||
@@ -102,7 +103,7 @@ export class CustomTile extends ImageTile {
|
||||
* A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be
|
||||
* used instead of defining each one separately in the `urls` option.
|
||||
* @property {string} [tierSizeCalculation] Tier size calculation method: `default` or `truncated`.
|
||||
* @property {import("../size.js").Size} [size] Size of the image.
|
||||
* @property {import("../size.js").Size} size
|
||||
* @property {import("../extent.js").Extent} [extent] Extent for the TileGrid that is created.
|
||||
* Default sets the TileGrid in the
|
||||
* fourth quadrant, meaning extent is `[0, -height, width, 0]`. To change the
|
||||
@@ -127,11 +128,11 @@ export class CustomTile extends ImageTile {
|
||||
class Zoomify extends TileImage {
|
||||
|
||||
/**
|
||||
* @param {Options=} opt_options Options.
|
||||
* @param {Options} opt_options Options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
|
||||
const options = opt_options || {};
|
||||
const options = opt_options;
|
||||
|
||||
const size = options.size;
|
||||
const tierSizeCalculation = options.tierSizeCalculation !== undefined ?
|
||||
@@ -198,7 +199,7 @@ class Zoomify extends TileImage {
|
||||
}
|
||||
const urls = expandUrl(url);
|
||||
|
||||
const tileWidth = tileSize * tilePixelRatio;
|
||||
let tileWidth = tileSize * tilePixelRatio;
|
||||
|
||||
/**
|
||||
* @param {string} template Template.
|
||||
@@ -262,6 +263,19 @@ class Zoomify extends TileImage {
|
||||
*/
|
||||
this.zDirection = options.zDirection;
|
||||
|
||||
// Server retina tile detection (non-standard):
|
||||
// Try loading the center tile for the highest resolution. If it is not
|
||||
// available, we are dealing with retina tiles, and need to adjust the
|
||||
// tile url calculation.
|
||||
const tileUrl = tileGrid.getTileCoordForCoordAndResolution(getCenter(tileGrid.getExtent()), resolutions[resolutions.length - 1]);
|
||||
const testTileUrl = tileUrlFunction(tileUrl, 1, null);
|
||||
const image = new Image();
|
||||
image.addEventListener('error', function() {
|
||||
tileWidth = tileSize;
|
||||
this.changed();
|
||||
}.bind(this));
|
||||
image.src = testTileUrl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -427,6 +427,7 @@ export function parseLiteralStyle(style) {
|
||||
const parsedSize = expressionToGlsl(vertContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER);
|
||||
const parsedOffset = expressionToGlsl(vertContext, offset, ValueTypes.NUMBER_ARRAY);
|
||||
const parsedTexCoord = expressionToGlsl(vertContext, texCoord, ValueTypes.NUMBER_ARRAY);
|
||||
const parsedRotation = expressionToGlsl(vertContext, rotation, ValueTypes.NUMBER);
|
||||
|
||||
/**
|
||||
* @type {import("../style/expressions.js").ParsingContext}
|
||||
@@ -439,7 +440,6 @@ export function parseLiteralStyle(style) {
|
||||
};
|
||||
const parsedColor = expressionToGlsl(fragContext, color, ValueTypes.COLOR);
|
||||
const parsedOpacity = expressionToGlsl(fragContext, opacity, ValueTypes.NUMBER);
|
||||
const parsedRotation = expressionToGlsl(fragContext, rotation, ValueTypes.NUMBER);
|
||||
|
||||
let opacityFilter = '1.0';
|
||||
const visibleSize = `vec2(${expressionToGlsl(fragContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER)}).x`;
|
||||
|
||||
Reference in New Issue
Block a user