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: >
|
||||
This example shows how several regular shapes
|
||||
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"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -59,18 +59,39 @@ const styles = {
|
||||
radius2: 0,
|
||||
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 features = new Array(count);
|
||||
const e = 4500000;
|
||||
for (let i = 0; i < count; ++i) {
|
||||
const coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
|
||||
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({
|
||||
|
||||
@@ -13,16 +13,17 @@ const vectorSource = new VectorSource();
|
||||
function createFeatures(stroke, fill, offSet = [0, 0]) {
|
||||
let 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({
|
||||
image: new RegularShape({
|
||||
fill: fill,
|
||||
stroke: stroke,
|
||||
points: 4,
|
||||
radius: 10,
|
||||
angle: Math.PI / 4
|
||||
angle: Math.PI / 4,
|
||||
displacement: [-15, 15]
|
||||
})
|
||||
}));
|
||||
vectorSource.addFeature(feature);
|
||||
|
||||
@@ -10,6 +10,7 @@ import RegularShape from './RegularShape.js';
|
||||
* @property {import("./Fill.js").default} [fill] Fill style.
|
||||
* @property {number} radius Circle radius.
|
||||
* @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,
|
||||
fill: options.fill,
|
||||
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({
|
||||
fill: this.getFill() ? this.getFill().clone() : undefined,
|
||||
stroke: this.getStroke() ? this.getStroke().clone() : undefined,
|
||||
radius: this.getRadius()
|
||||
radius: this.getRadius(),
|
||||
displacement: this.getDisplacement().slice()
|
||||
});
|
||||
style.setOpacity(this.getOpacity());
|
||||
style.setScale(this.getScale());
|
||||
|
||||
@@ -33,6 +33,7 @@ import ImageStyle from './Image.js';
|
||||
* 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
|
||||
* 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`,
|
||||
* `top-left` or `top-right`.
|
||||
* @property {number} [opacity=1] Opacity of the icon.
|
||||
@@ -84,6 +85,7 @@ class Icon extends ImageStyle {
|
||||
opacity: opacity,
|
||||
rotation: rotation,
|
||||
scale: scale,
|
||||
displacement: options.displacement !== undefined ? options.displacement : [0, 0],
|
||||
rotateWithView: rotateWithView
|
||||
});
|
||||
|
||||
@@ -177,7 +179,6 @@ class Icon extends ImageStyle {
|
||||
* @type {Array<number>}
|
||||
*/
|
||||
this.offset_ = options.offset !== undefined ? options.offset : [0, 0];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./IconOrigin.js").default}
|
||||
@@ -336,6 +337,7 @@ class Icon extends ImageStyle {
|
||||
return this.origin_;
|
||||
}
|
||||
let offset = this.offset_;
|
||||
const displacement = this.getDisplacement();
|
||||
|
||||
if (this.offsetOrigin_ != IconOrigin.TOP_LEFT) {
|
||||
const size = this.getSize();
|
||||
@@ -353,6 +355,8 @@ class Icon extends ImageStyle {
|
||||
offset[1] = iconImageSize[1] - size[1] - offset[1];
|
||||
}
|
||||
}
|
||||
offset[0] += displacement[0];
|
||||
offset[1] += displacement[1];
|
||||
this.origin_ = offset;
|
||||
return this.origin_;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {abstract} from '../util.js';
|
||||
* @property {boolean} rotateWithView
|
||||
* @property {number} rotation
|
||||
* @property {number} scale
|
||||
* @property {Array<number>} displacement
|
||||
*/
|
||||
|
||||
|
||||
@@ -51,6 +52,12 @@ class ImageStyle {
|
||||
*/
|
||||
this.scale_ = options.scale;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<number>}
|
||||
*/
|
||||
this.displacement_ = options.displacement;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +70,8 @@ class ImageStyle {
|
||||
opacity: this.getOpacity(),
|
||||
scale: this.getScale(),
|
||||
rotation: this.getRotation(),
|
||||
rotateWithView: this.getRotateWithView()
|
||||
rotateWithView: this.getRotateWithView(),
|
||||
displacement: this.getDisplacement().slice()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,6 +111,15 @@ class ImageStyle {
|
||||
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
|
||||
* symbolizer.
|
||||
|
||||
@@ -20,6 +20,7 @@ import ImageStyle from './Image.js';
|
||||
* @property {number} [radius1] Outer 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 {Array<number>} [displacement=[0,0]] Displacement of the shape
|
||||
* @property {import("./Stroke.js").default} [stroke] Stroke style.
|
||||
* @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
|
||||
* @property {boolean} [rotateWithView=false] Whether to rotate the shape with the view.
|
||||
@@ -61,7 +62,8 @@ class RegularShape extends ImageStyle {
|
||||
opacity: 1,
|
||||
rotateWithView: rotateWithView,
|
||||
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(),
|
||||
stroke: this.getStroke() ? this.getStroke().clone() : undefined,
|
||||
rotation: this.getRotation(),
|
||||
rotateWithView: this.getRotateWithView()
|
||||
rotateWithView: this.getRotateWithView(),
|
||||
displacement: this.getDisplacement().slice()
|
||||
});
|
||||
style.setOpacity(this.getOpacity());
|
||||
style.setScale(this.getScale());
|
||||
@@ -353,12 +356,13 @@ class RegularShape extends ImageStyle {
|
||||
// canvas.width and height are rounded to the closest integer
|
||||
size = this.canvas_.width;
|
||||
const imageSize = size;
|
||||
const displacement = this.getDisplacement();
|
||||
|
||||
this.draw_(renderOptions, context, 0, 0);
|
||||
|
||||
this.createHitDetectionCanvas_(renderOptions);
|
||||
|
||||
this.anchor_ = [size / 2, size / 2];
|
||||
this.anchor_ = [size / 2 - displacement[0], size / 2 + displacement[1]];
|
||||
this.size_ = [size, size];
|
||||
this.imageSize_ = [imageSize, imageSize];
|
||||
}
|
||||
|
||||
@@ -97,22 +97,26 @@ describe('ol.style.Icon', function() {
|
||||
color: [1, 2, 3, 0.4],
|
||||
src: src,
|
||||
offset: [1, 2],
|
||||
size: [10, 12]
|
||||
size: [10, 12],
|
||||
displacement: [5, 6]
|
||||
});
|
||||
const clone = original.clone();
|
||||
expect(original.getAnchor()).not.to.be(clone.getAnchor());
|
||||
expect(original.offset_).not.to.be(clone.offset_);
|
||||
expect(original.getColor()).not.to.be(clone.getColor());
|
||||
expect(original.getSize()).not.to.be(clone.getSize());
|
||||
expect(original.getDisplacement()).not.to.be(clone.getDisplacement());
|
||||
|
||||
clone.anchor_[0] = 0;
|
||||
clone.offset_[0] = 0;
|
||||
clone.color_[0] = 0;
|
||||
clone.size_[0] = 5;
|
||||
clone.displacement_[0] = 10;
|
||||
expect(original.anchor_).not.to.eql(clone.anchor_);
|
||||
expect(original.offset_).not.to.eql(clone.offset_);
|
||||
expect(original.color_).not.to.eql(clone.color_);
|
||||
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;
|
||||
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() {
|
||||
|
||||
@@ -82,6 +82,24 @@ describe('ol.style.RegularShape', function() {
|
||||
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() {
|
||||
@@ -108,7 +126,8 @@ describe('ol.style.RegularShape', function() {
|
||||
color: '#319FD3'
|
||||
}),
|
||||
rotation: 2,
|
||||
rotateWithView: true
|
||||
rotateWithView: true,
|
||||
displacement: [10, 20]
|
||||
});
|
||||
original.setOpacity(0.5);
|
||||
original.setScale(1.5);
|
||||
@@ -123,6 +142,8 @@ describe('ol.style.RegularShape', function() {
|
||||
expect(original.getRotateWithView()).to.eql(clone.getRotateWithView());
|
||||
expect(original.getScale()).to.eql(clone.getScale());
|
||||
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() {
|
||||
@@ -132,11 +153,13 @@ describe('ol.style.RegularShape', function() {
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: '#319FD3'
|
||||
})
|
||||
}),
|
||||
displacement: [0, 5]
|
||||
});
|
||||
const clone = original.clone();
|
||||
expect(original.getFill()).to.not.be(clone.getFill());
|
||||
expect(original.getStroke()).to.not.be(clone.getStroke());
|
||||
expect(original.getDisplacement()).to.not.be(clone.getDisplacement());
|
||||
|
||||
clone.getFill().setColor('#012345');
|
||||
clone.getStroke().setColor('#012345');
|
||||
|
||||
Reference in New Issue
Block a user