Merge pull request #10012 from tschaub/more-geographic

Use the user projection for the map event coordinate
This commit is contained in:
Tim Schaub
2019-09-26 17:40:05 +02:00
committed by GitHub
9 changed files with 258 additions and 10 deletions

View File

@@ -36,7 +36,7 @@ class MapBrowserEvent extends MapEvent {
this.pixel_ = null;
/**
* The coordinate in view projection corresponding to the original browser event.
* The coordinate in the user projection corresponding to the original browser event.
* @type {import("./coordinate.js").Coordinate}
*/
this.coordinate_ = null;
@@ -68,13 +68,14 @@ class MapBrowserEvent extends MapEvent {
}
/**
* The coordinate in view projection corresponding to the original browser event.
* The coordinate corresponding to the original browser event. This will be in the user
* projection if one is set. Otherwise it will be in the view projection.
* @type {import("./coordinate.js").Coordinate}
* @api
*/
get coordinate() {
if (!this.coordinate_) {
this.coordinate_ = this.map.getCoordinateFromPixelInternal(this.pixel);
this.coordinate_ = this.map.getCoordinateFromPixel(this.pixel);
}
return this.coordinate_;
}

View File

@@ -1237,6 +1237,17 @@ class View extends BaseObject {
* @api
*/
adjustResolution(ratio, opt_anchor) {
const anchor = opt_anchor && fromUserCoordinate(opt_anchor, this.getProjection());
this.adjustResolutionInternal(ratio, anchor);
}
/**
* Multiply the view resolution by a ratio, optionally using an anchor. Any resolution
* constraint will apply.
* @param {number} ratio The ratio to apply on the view resolution.
* @param {import("./coordinate.js").Coordinate=} opt_anchor The origin of the transformation.
*/
adjustResolutionInternal(ratio, opt_anchor) {
const isMoving = this.getAnimating() || this.getInteracting();
const size = this.getSizeFromViewport_(this.getRotation());
const newResolution = this.constraints_.resolution(this.targetResolution_ * ratio, 0, size, isMoving);
@@ -1448,6 +1459,18 @@ class View extends BaseObject {
* @api
*/
endInteraction(opt_duration, opt_resolutionDirection, opt_anchor) {
const anchor = opt_anchor && fromUserCoordinate(opt_anchor, this.getProjection());
this.endInteractionInternal(opt_duration, opt_resolutionDirection, anchor);
}
/**
* Notify the View that an interaction has ended. The view state will be resolved
* to a stable one if needed (depending on its constraints).
* @param {number=} opt_duration Animation duration in ms.
* @param {number=} opt_resolutionDirection Which direction to zoom.
* @param {import("./coordinate.js").Coordinate=} opt_anchor The origin of the transformation.
*/
endInteractionInternal(opt_duration, opt_resolutionDirection, opt_anchor) {
this.setHint(ViewHint.INTERACTING, -1);
this.resolveConstraints(opt_duration, opt_resolutionDirection, opt_anchor);

View File

@@ -91,7 +91,7 @@ class DragRotateAndZoom extends PointerInteraction {
}
this.lastAngle_ = theta;
if (this.lastMagnitude_ !== undefined) {
view.adjustResolution(this.lastMagnitude_ / magnitude);
view.adjustResolutionInternal(this.lastMagnitude_ / magnitude);
}
if (this.lastMagnitude_ !== undefined) {
this.lastScaleDelta_ = this.lastMagnitude_ / magnitude;

View File

@@ -122,7 +122,7 @@ export function pan(view, delta, opt_duration) {
/**
* @param {import("../View.js").default} view View.
* @param {number} delta Delta from previous zoom level.
* @param {import("../coordinate.js").Coordinate=} opt_anchor Anchor coordinate.
* @param {import("../coordinate.js").Coordinate=} opt_anchor Anchor coordinate in the user projection.
* @param {number=} opt_duration Duration.
*/
export function zoomByDelta(view, delta, opt_anchor, opt_duration) {
@@ -138,7 +138,7 @@ export function zoomByDelta(view, delta, opt_anchor, opt_duration) {
if (view.getAnimating()) {
view.cancelAnimations();
}
view.animateInternal({
view.animate({
resolution: newResolution,
anchor: opt_anchor,
duration: opt_duration !== undefined ? opt_duration : 250,

View File

@@ -95,7 +95,7 @@ class PinchZoom extends PointerInteraction {
// scale, bypass the resolution constraint
map.render();
view.adjustResolution(scaleDelta, this.anchor_);
view.adjustResolutionInternal(scaleDelta, this.anchor_);
}
/**

View File

@@ -0,0 +1,143 @@
import {Map, View} from '../../../src/ol/index.js';
import MapBrowserEvent from '../../../src/ol/MapBrowserEvent.js';
import Event from '../../../src/ol/events/Event.js';
import {useGeographic, clearUserProjection} from '../../../src/ol/proj.js';
function createMap() {
const size = 256;
const target = document.createElement('div');
Object.assign(target.style, {
width: `${size}px`,
height: `${size}px`,
position: 'absolute',
top: 0,
left: 0
});
document.body.appendChild(target);
const map = new Map({
target: target,
view: new View({
center: [0, 0],
zoom: 0
})
});
return {map, target, size};
}
describe('ol/MapBrowserEvent', function() {
describe('pixel', function() {
let ref;
beforeEach(() => {
ref = createMap();
});
afterEach(() => {
ref.map.dispose();
document.body.removeChild(ref.target);
});
it('is the pixel position of the event', () => {
const x = 10;
const y = 15;
const event = new Event();
event.clientX = x;
event.clientY = y;
const mapEvent = new MapBrowserEvent('test', ref.map, event);
expect(mapEvent.pixel).to.eql([x, y]);
});
it('is settable', () => {
const x = 10;
const y = 15;
const event = new Event();
event.clientX = x;
event.clientY = y;
const mapEvent = new MapBrowserEvent('test', ref.map, event);
expect(mapEvent.pixel).to.eql([x, y]);
const pixel = [x + 5, y + 5];
mapEvent.pixel = pixel;
expect(mapEvent.pixel).to.eql(pixel);
});
});
describe('coordinate', function() {
let ref;
beforeEach(() => {
ref = createMap();
ref.map.renderSync();
});
afterEach(() => {
ref.map.dispose();
document.body.removeChild(ref.target);
});
it('is the map coordinate of the event', () => {
const x = ref.size / 2;
const y = ref.size / 2;
const event = new Event();
event.clientX = x;
event.clientY = y;
const mapEvent = new MapBrowserEvent('test', ref.map, event);
expect(mapEvent.coordinate).to.eql([0, 0]);
});
it('is settable', () => {
const x = ref.size / 2;
const y = ref.size / 2;
const event = new Event();
event.clientX = x;
event.clientY = y;
const mapEvent = new MapBrowserEvent('test', ref.map, event);
expect(mapEvent.coordinate).to.eql([0, 0]);
const coordinate = [1, 2];
mapEvent.coordinate = coordinate;
expect(mapEvent.coordinate).to.eql(coordinate);
});
});
describe('coordinate - with useGeographic()', function() {
let ref;
beforeEach(() => {
useGeographic();
ref = createMap();
ref.map.renderSync();
});
afterEach(() => {
clearUserProjection();
ref.map.dispose();
document.body.removeChild(ref.target);
});
it('is the geographic coordinate of the event', () => {
const x = ref.size / 4;
const y = ref.size / 4;
const event = new Event();
event.clientX = x;
event.clientY = y;
const mapEvent = new MapBrowserEvent('test', ref.map, event);
const coord = mapEvent.coordinate;
expect(coord[0]).to.be(-90);
expect(coord[1]).to.roughlyEqual(66.5132, 1e-4);
});
});
});

View File

@@ -4,7 +4,7 @@ import {listen} from '../../../src/ol/events.js';
import {DEVICE_PIXEL_RATIO} from '../../../src/ol/has.js';
import Event from '../../../src/ol/events/Event.js';
describe('ol.MapBrowserEventHandler', function() {
describe('ol/MapBrowserEventHandler', function() {
describe('#emulateClick_', function() {
let clock;
let handler;

View File

@@ -1,7 +1,8 @@
import Map from '../../../../src/ol/Map.js';
import {Map, View} from '../../../../src/ol/index.js';
import EventTarget from '../../../../src/ol/events/Target.js';
import Interaction from '../../../../src/ol/interaction/Interaction.js';
import Interaction, {zoomByDelta} from '../../../../src/ol/interaction/Interaction.js';
import {FALSE} from '../../../../src/ol/functions.js';
import {useGeographic, clearUserProjection} from '../../../../src/ol/proj.js';
describe('ol.interaction.Interaction', function() {
@@ -87,3 +88,25 @@ describe('ol.interaction.Interaction', function() {
});
});
describe('zoomByDelta - useGeographic', () => {
beforeEach(useGeographic);
afterEach(clearUserProjection);
it('works with a user projection set', done => {
const view = new View({
center: [0, 0],
zoom: 0
});
const anchor = [90, 45];
const duration = 10;
zoomByDelta(view, 1, anchor, duration);
setTimeout(() => {
const center = view.getCenter();
expect(center[0]).to.be(45);
expect(center[1]).to.roughlyEqual(24.4698, 1e-4);
done();
}, 2 * duration);
});
});

View File

@@ -8,6 +8,7 @@ import {createEmpty} from '../../../src/ol/extent.js';
import Circle from '../../../src/ol/geom/Circle.js';
import LineString from '../../../src/ol/geom/LineString.js';
import Point from '../../../src/ol/geom/Point.js';
import {useGeographic, clearUserProjection} from '../../../src/ol/proj.js';
describe('ol.View', function() {
@@ -1890,6 +1891,63 @@ describe('ol.View', function() {
expect(view.getCenter()).to.eql([0, 100 - halfSize]);
});
});
describe('#adjustZoom() - useGeographic', () => {
beforeEach(useGeographic);
afterEach(clearUserProjection);
it('changes view resolution', () => {
const view = new View({
resolution: 1,
resolutions: [4, 2, 1, 0.5, 0.25]
});
view.adjustZoom(1);
expect(view.getResolution()).to.be(0.5);
view.adjustZoom(-1);
expect(view.getResolution()).to.be(1);
view.adjustZoom(2);
expect(view.getResolution()).to.be(0.25);
view.adjustZoom(-2);
expect(view.getResolution()).to.be(1);
});
it('changes view resolution and center relative to the anchor', function() {
const view = new View({
center: [0, 0],
zoom: 0
});
let center;
view.adjustZoom(1, [90, 45]);
center = view.getCenter();
expect(center[0]).to.be(45);
expect(center[1]).to.roughlyEqual(24.4698, 1e-4);
view.adjustZoom(-1, [90, 45]);
center = view.getCenter();
expect(center[0]).to.roughlyEqual(0, 1e-10);
expect(center[1]).to.roughlyEqual(0, 1e-10);
view.adjustZoom(2, [-90, -45]);
center = view.getCenter();
expect(center[0]).to.be(-67.5);
expect(center[1]).to.roughlyEqual(-35.3836, 1e-4);
view.adjustZoom(-2, [-90, -45]);
center = view.getCenter();
expect(center[0]).to.roughlyEqual(0, 1e-10);
expect(center[1]).to.roughlyEqual(0, 1e-10);
});
});
});
describe('does not start unexpected animations during interaction', function() {