Merge pull request #10430 from Razi91/offset-RegularShape
Offset regular shape
This commit is contained in:
@@ -5,7 +5,9 @@ shortdesc: Example of some Regular Shape styles.
|
|||||||
docs: >
|
docs: >
|
||||||
This example shows how several regular shapes
|
This example shows how several regular shapes
|
||||||
or symbols (representing `x`, `cross`, `star`,
|
or symbols (representing `x`, `cross`, `star`,
|
||||||
`triangle` and `square`) can be created.
|
`triangle`, `square` and `stacked`) can be created.
|
||||||
|
|
||||||
|
Style `stacked` represents possility to stack multiple shapes with offset
|
||||||
tags: "vector, symbol, regularshape, style, square, cross, star, triangle, x"
|
tags: "vector, symbol, regularshape, style, square, cross, star, triangle, x"
|
||||||
---
|
---
|
||||||
<div id="map" class="map"></div>
|
<div id="map" class="map"></div>
|
||||||
|
|||||||
@@ -59,18 +59,39 @@ const styles = {
|
|||||||
radius2: 0,
|
radius2: 0,
|
||||||
angle: Math.PI / 4
|
angle: Math.PI / 4
|
||||||
})
|
})
|
||||||
})
|
}),
|
||||||
|
'stacked': [
|
||||||
|
new Style({
|
||||||
|
image: new RegularShape({
|
||||||
|
fill: fill,
|
||||||
|
stroke: stroke,
|
||||||
|
points: 4,
|
||||||
|
radius: 5,
|
||||||
|
angle: Math.PI / 4,
|
||||||
|
displacement: [0, 10]
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
new Style({
|
||||||
|
image: new RegularShape({
|
||||||
|
fill: fill,
|
||||||
|
stroke: stroke,
|
||||||
|
points: 4,
|
||||||
|
radius: 10,
|
||||||
|
angle: Math.PI / 4
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const styleKeys = ['x', 'cross', 'star', 'triangle', 'square'];
|
const styleKeys = ['x', 'cross', 'star', 'triangle', 'square', 'stacked'];
|
||||||
const count = 250;
|
const count = 250;
|
||||||
const features = new Array(count);
|
const features = new Array(count);
|
||||||
const e = 4500000;
|
const e = 4500000;
|
||||||
for (let i = 0; i < count; ++i) {
|
for (let i = 0; i < count; ++i) {
|
||||||
const coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
|
const coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
|
||||||
features[i] = new Feature(new Point(coordinates));
|
features[i] = new Feature(new Point(coordinates));
|
||||||
features[i].setStyle(styles[styleKeys[Math.floor(Math.random() * 5)]]);
|
features[i].setStyle(styles[styleKeys[Math.floor(Math.random() * 6)]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const source = new VectorSource({
|
const source = new VectorSource({
|
||||||
|
|||||||
@@ -13,16 +13,17 @@ const vectorSource = new VectorSource();
|
|||||||
function createFeatures(stroke, fill, offSet = [0, 0]) {
|
function createFeatures(stroke, fill, offSet = [0, 0]) {
|
||||||
let feature;
|
let feature;
|
||||||
feature = new Feature({
|
feature = new Feature({
|
||||||
geometry: new Point([-15 + offSet[0], 15 + offSet[1]])
|
geometry: new Point([offSet[0], offSet[1]])
|
||||||
});
|
});
|
||||||
// square
|
// square with offset
|
||||||
feature.setStyle(new Style({
|
feature.setStyle(new Style({
|
||||||
image: new RegularShape({
|
image: new RegularShape({
|
||||||
fill: fill,
|
fill: fill,
|
||||||
stroke: stroke,
|
stroke: stroke,
|
||||||
points: 4,
|
points: 4,
|
||||||
radius: 10,
|
radius: 10,
|
||||||
angle: Math.PI / 4
|
angle: Math.PI / 4,
|
||||||
|
displacement: [-15, 15]
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
vectorSource.addFeature(feature);
|
vectorSource.addFeature(feature);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import RegularShape from './RegularShape.js';
|
|||||||
* @property {import("./Fill.js").default} [fill] Fill style.
|
* @property {import("./Fill.js").default} [fill] Fill style.
|
||||||
* @property {number} radius Circle radius.
|
* @property {number} radius Circle radius.
|
||||||
* @property {import("./Stroke.js").default} [stroke] Stroke style.
|
* @property {import("./Stroke.js").default} [stroke] Stroke style.
|
||||||
|
* @property {Array<number>} [displacement=[0,0]] displacement
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +31,8 @@ class CircleStyle extends RegularShape {
|
|||||||
points: Infinity,
|
points: Infinity,
|
||||||
fill: options.fill,
|
fill: options.fill,
|
||||||
radius: options.radius,
|
radius: options.radius,
|
||||||
stroke: options.stroke
|
stroke: options.stroke,
|
||||||
|
displacement: options.displacement !== undefined ? options.displacement : [0, 0]
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -45,7 +47,8 @@ class CircleStyle extends RegularShape {
|
|||||||
const style = new CircleStyle({
|
const style = new CircleStyle({
|
||||||
fill: this.getFill() ? this.getFill().clone() : undefined,
|
fill: this.getFill() ? this.getFill().clone() : undefined,
|
||||||
stroke: this.getStroke() ? this.getStroke().clone() : undefined,
|
stroke: this.getStroke() ? this.getStroke().clone() : undefined,
|
||||||
radius: this.getRadius()
|
radius: this.getRadius(),
|
||||||
|
displacement: this.getDisplacement().slice()
|
||||||
});
|
});
|
||||||
style.setOpacity(this.getOpacity());
|
style.setOpacity(this.getOpacity());
|
||||||
style.setScale(this.getScale());
|
style.setScale(this.getScale());
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import ImageStyle from './Image.js';
|
|||||||
* to provide the size of the image, with the `imgSize` option.
|
* to provide the size of the image, with the `imgSize` option.
|
||||||
* @property {Array<number>} [offset=[0, 0]] Offset, which, together with the size and the offset origin, define the
|
* @property {Array<number>} [offset=[0, 0]] Offset, which, together with the size and the offset origin, define the
|
||||||
* sub-rectangle to use from the original icon image.
|
* sub-rectangle to use from the original icon image.
|
||||||
|
* @property {Array<number>} [displacement=[0,0]] Displacement the icon
|
||||||
* @property {import("./IconOrigin.js").default} [offsetOrigin='top-left'] Origin of the offset: `bottom-left`, `bottom-right`,
|
* @property {import("./IconOrigin.js").default} [offsetOrigin='top-left'] Origin of the offset: `bottom-left`, `bottom-right`,
|
||||||
* `top-left` or `top-right`.
|
* `top-left` or `top-right`.
|
||||||
* @property {number} [opacity=1] Opacity of the icon.
|
* @property {number} [opacity=1] Opacity of the icon.
|
||||||
@@ -84,6 +85,7 @@ class Icon extends ImageStyle {
|
|||||||
opacity: opacity,
|
opacity: opacity,
|
||||||
rotation: rotation,
|
rotation: rotation,
|
||||||
scale: scale,
|
scale: scale,
|
||||||
|
displacement: options.displacement !== undefined ? options.displacement : [0, 0],
|
||||||
rotateWithView: rotateWithView
|
rotateWithView: rotateWithView
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -177,7 +179,6 @@ class Icon extends ImageStyle {
|
|||||||
* @type {Array<number>}
|
* @type {Array<number>}
|
||||||
*/
|
*/
|
||||||
this.offset_ = options.offset !== undefined ? options.offset : [0, 0];
|
this.offset_ = options.offset !== undefined ? options.offset : [0, 0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @type {import("./IconOrigin.js").default}
|
* @type {import("./IconOrigin.js").default}
|
||||||
@@ -336,6 +337,7 @@ class Icon extends ImageStyle {
|
|||||||
return this.origin_;
|
return this.origin_;
|
||||||
}
|
}
|
||||||
let offset = this.offset_;
|
let offset = this.offset_;
|
||||||
|
const displacement = this.getDisplacement();
|
||||||
|
|
||||||
if (this.offsetOrigin_ != IconOrigin.TOP_LEFT) {
|
if (this.offsetOrigin_ != IconOrigin.TOP_LEFT) {
|
||||||
const size = this.getSize();
|
const size = this.getSize();
|
||||||
@@ -353,6 +355,8 @@ class Icon extends ImageStyle {
|
|||||||
offset[1] = iconImageSize[1] - size[1] - offset[1];
|
offset[1] = iconImageSize[1] - size[1] - offset[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
offset[0] += displacement[0];
|
||||||
|
offset[1] += displacement[1];
|
||||||
this.origin_ = offset;
|
this.origin_ = offset;
|
||||||
return this.origin_;
|
return this.origin_;
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-1
@@ -10,6 +10,7 @@ import {abstract} from '../util.js';
|
|||||||
* @property {boolean} rotateWithView
|
* @property {boolean} rotateWithView
|
||||||
* @property {number} rotation
|
* @property {number} rotation
|
||||||
* @property {number} scale
|
* @property {number} scale
|
||||||
|
* @property {Array<number>} displacement
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -51,6 +52,12 @@ class ImageStyle {
|
|||||||
*/
|
*/
|
||||||
this.scale_ = options.scale;
|
this.scale_ = options.scale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Array<number>}
|
||||||
|
*/
|
||||||
|
this.displacement_ = options.displacement;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,7 +70,8 @@ class ImageStyle {
|
|||||||
opacity: this.getOpacity(),
|
opacity: this.getOpacity(),
|
||||||
scale: this.getScale(),
|
scale: this.getScale(),
|
||||||
rotation: this.getRotation(),
|
rotation: this.getRotation(),
|
||||||
rotateWithView: this.getRotateWithView()
|
rotateWithView: this.getRotateWithView(),
|
||||||
|
displacement: this.getDisplacement().slice()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,6 +111,15 @@ class ImageStyle {
|
|||||||
return this.scale_;
|
return this.scale_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the displacement of the shape
|
||||||
|
* @return {Array<number>} Shape's center displacement
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
getDisplacement() {
|
||||||
|
return this.displacement_;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the anchor point in pixels. The anchor determines the center point for the
|
* Get the anchor point in pixels. The anchor determines the center point for the
|
||||||
* symbolizer.
|
* symbolizer.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import ImageStyle from './Image.js';
|
|||||||
* @property {number} [radius1] Outer radius of a star.
|
* @property {number} [radius1] Outer radius of a star.
|
||||||
* @property {number} [radius2] Inner radius of a star.
|
* @property {number} [radius2] Inner radius of a star.
|
||||||
* @property {number} [angle=0] Shape's angle in radians. A value of 0 will have one of the shape's point facing up.
|
* @property {number} [angle=0] Shape's angle in radians. A value of 0 will have one of the shape's point facing up.
|
||||||
|
* @property {Array<number>} [displacement=[0,0]] Displacement of the shape
|
||||||
* @property {import("./Stroke.js").default} [stroke] Stroke style.
|
* @property {import("./Stroke.js").default} [stroke] Stroke style.
|
||||||
* @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
|
* @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
|
||||||
* @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view.
|
* @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view.
|
||||||
@@ -61,7 +62,8 @@ class RegularShape extends ImageStyle {
|
|||||||
opacity: 1,
|
opacity: 1,
|
||||||
rotateWithView: rotateWithView,
|
rotateWithView: rotateWithView,
|
||||||
rotation: options.rotation !== undefined ? options.rotation : 0,
|
rotation: options.rotation !== undefined ? options.rotation : 0,
|
||||||
scale: 1
|
scale: 1,
|
||||||
|
displacement: options.displacement !== undefined ? options.displacement : [0, 0]
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,7 +162,8 @@ class RegularShape extends ImageStyle {
|
|||||||
angle: this.getAngle(),
|
angle: this.getAngle(),
|
||||||
stroke: this.getStroke() ? this.getStroke().clone() : undefined,
|
stroke: this.getStroke() ? this.getStroke().clone() : undefined,
|
||||||
rotation: this.getRotation(),
|
rotation: this.getRotation(),
|
||||||
rotateWithView: this.getRotateWithView()
|
rotateWithView: this.getRotateWithView(),
|
||||||
|
displacement: this.getDisplacement().slice()
|
||||||
});
|
});
|
||||||
style.setOpacity(this.getOpacity());
|
style.setOpacity(this.getOpacity());
|
||||||
style.setScale(this.getScale());
|
style.setScale(this.getScale());
|
||||||
@@ -353,12 +356,13 @@ class RegularShape extends ImageStyle {
|
|||||||
// canvas.width and height are rounded to the closest integer
|
// canvas.width and height are rounded to the closest integer
|
||||||
size = this.canvas_.width;
|
size = this.canvas_.width;
|
||||||
const imageSize = size;
|
const imageSize = size;
|
||||||
|
const displacement = this.getDisplacement();
|
||||||
|
|
||||||
this.draw_(renderOptions, context, 0, 0);
|
this.draw_(renderOptions, context, 0, 0);
|
||||||
|
|
||||||
this.createHitDetectionCanvas_(renderOptions);
|
this.createHitDetectionCanvas_(renderOptions);
|
||||||
|
|
||||||
this.anchor_ = [size / 2, size / 2];
|
this.anchor_ = [size / 2 - displacement[0], size / 2 + displacement[1]];
|
||||||
this.size_ = [size, size];
|
this.size_ = [size, size];
|
||||||
this.imageSize_ = [imageSize, imageSize];
|
this.imageSize_ = [imageSize, imageSize];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,22 +97,26 @@ describe('ol.style.Icon', function() {
|
|||||||
color: [1, 2, 3, 0.4],
|
color: [1, 2, 3, 0.4],
|
||||||
src: src,
|
src: src,
|
||||||
offset: [1, 2],
|
offset: [1, 2],
|
||||||
size: [10, 12]
|
size: [10, 12],
|
||||||
|
displacement: [5, 6]
|
||||||
});
|
});
|
||||||
const clone = original.clone();
|
const clone = original.clone();
|
||||||
expect(original.getAnchor()).not.to.be(clone.getAnchor());
|
expect(original.getAnchor()).not.to.be(clone.getAnchor());
|
||||||
expect(original.offset_).not.to.be(clone.offset_);
|
expect(original.offset_).not.to.be(clone.offset_);
|
||||||
expect(original.getColor()).not.to.be(clone.getColor());
|
expect(original.getColor()).not.to.be(clone.getColor());
|
||||||
expect(original.getSize()).not.to.be(clone.getSize());
|
expect(original.getSize()).not.to.be(clone.getSize());
|
||||||
|
expect(original.getDisplacement()).not.to.be(clone.getDisplacement());
|
||||||
|
|
||||||
clone.anchor_[0] = 0;
|
clone.anchor_[0] = 0;
|
||||||
clone.offset_[0] = 0;
|
clone.offset_[0] = 0;
|
||||||
clone.color_[0] = 0;
|
clone.color_[0] = 0;
|
||||||
clone.size_[0] = 5;
|
clone.size_[0] = 5;
|
||||||
|
clone.displacement_[0] = 10;
|
||||||
expect(original.anchor_).not.to.eql(clone.anchor_);
|
expect(original.anchor_).not.to.eql(clone.anchor_);
|
||||||
expect(original.offset_).not.to.eql(clone.offset_);
|
expect(original.offset_).not.to.eql(clone.offset_);
|
||||||
expect(original.color_).not.to.eql(clone.color_);
|
expect(original.color_).not.to.eql(clone.color_);
|
||||||
expect(original.size_).not.to.eql(clone.size_);
|
expect(original.size_).not.to.eql(clone.size_);
|
||||||
|
expect(original.displacement_).not.to.eql(clone.displacement_);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -229,6 +233,18 @@ describe('ol.style.Icon', function() {
|
|||||||
iconStyle.iconImage_.size_ = imageSize;
|
iconStyle.iconImage_.size_ = imageSize;
|
||||||
expect(iconStyle.getOrigin()).to.eql([92, 20]);
|
expect(iconStyle.getOrigin()).to.eql([92, 20]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses a top right offset origin + displacement', function() {
|
||||||
|
const iconStyle = new Icon({
|
||||||
|
src: 'test.png',
|
||||||
|
size: size,
|
||||||
|
offset: offset,
|
||||||
|
offsetOrigin: 'top-right',
|
||||||
|
displacement: [20, 10]
|
||||||
|
});
|
||||||
|
iconStyle.iconImage_.size_ = imageSize;
|
||||||
|
expect(iconStyle.getOrigin()).to.eql([92 + 20, 20 + 10]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#getImageSize', function() {
|
describe('#getImageSize', function() {
|
||||||
|
|||||||
@@ -82,6 +82,24 @@ describe('ol.style.RegularShape', function() {
|
|||||||
expect(style.getHitDetectionImageSize()).to.eql([21, 21]);
|
expect(style.getHitDetectionImageSize()).to.eql([21, 21]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('sets default displacement [0, 0]', function() {
|
||||||
|
const style = new RegularShape({
|
||||||
|
radius: 5
|
||||||
|
});
|
||||||
|
expect(style.getDisplacement()).to.an('array');
|
||||||
|
expect(style.getDisplacement()[0]).to.eql(0);
|
||||||
|
expect(style.getDisplacement()[1]).to.eql(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can use offset', function() {
|
||||||
|
const style = new RegularShape({
|
||||||
|
radius: 5,
|
||||||
|
displacement: [10, 20]
|
||||||
|
});
|
||||||
|
expect(style.getDisplacement()).to.an('array');
|
||||||
|
expect(style.getDisplacement()[0]).to.eql(10);
|
||||||
|
expect(style.getDisplacement()[1]).to.eql(20);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#clone', function() {
|
describe('#clone', function() {
|
||||||
@@ -108,7 +126,8 @@ describe('ol.style.RegularShape', function() {
|
|||||||
color: '#319FD3'
|
color: '#319FD3'
|
||||||
}),
|
}),
|
||||||
rotation: 2,
|
rotation: 2,
|
||||||
rotateWithView: true
|
rotateWithView: true,
|
||||||
|
displacement: [10, 20]
|
||||||
});
|
});
|
||||||
original.setOpacity(0.5);
|
original.setOpacity(0.5);
|
||||||
original.setScale(1.5);
|
original.setScale(1.5);
|
||||||
@@ -123,6 +142,8 @@ describe('ol.style.RegularShape', function() {
|
|||||||
expect(original.getRotateWithView()).to.eql(clone.getRotateWithView());
|
expect(original.getRotateWithView()).to.eql(clone.getRotateWithView());
|
||||||
expect(original.getScale()).to.eql(clone.getScale());
|
expect(original.getScale()).to.eql(clone.getScale());
|
||||||
expect(original.getStroke().getColor()).to.eql(clone.getStroke().getColor());
|
expect(original.getStroke().getColor()).to.eql(clone.getStroke().getColor());
|
||||||
|
expect(original.getDisplacement()[0]).to.eql(clone.getDisplacement()[0]);
|
||||||
|
expect(original.getDisplacement()[1]).to.eql(clone.getDisplacement()[1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('the clone does not reference the same objects as the original', function() {
|
it('the clone does not reference the same objects as the original', function() {
|
||||||
@@ -132,11 +153,13 @@ describe('ol.style.RegularShape', function() {
|
|||||||
}),
|
}),
|
||||||
stroke: new Stroke({
|
stroke: new Stroke({
|
||||||
color: '#319FD3'
|
color: '#319FD3'
|
||||||
})
|
}),
|
||||||
|
displacement: [0, 5]
|
||||||
});
|
});
|
||||||
const clone = original.clone();
|
const clone = original.clone();
|
||||||
expect(original.getFill()).to.not.be(clone.getFill());
|
expect(original.getFill()).to.not.be(clone.getFill());
|
||||||
expect(original.getStroke()).to.not.be(clone.getStroke());
|
expect(original.getStroke()).to.not.be(clone.getStroke());
|
||||||
|
expect(original.getDisplacement()).to.not.be(clone.getDisplacement());
|
||||||
|
|
||||||
clone.getFill().setColor('#012345');
|
clone.getFill().setColor('#012345');
|
||||||
clone.getStroke().setColor('#012345');
|
clone.getStroke().setColor('#012345');
|
||||||
|
|||||||
Reference in New Issue
Block a user