开放层图标用户免费转换



在我的应用程序中,我编写了一个ol.interaction.Draw代码,允许我在地图视图上按比例绘制,旋转和缩放图标。绘制图标后,我仍然可以缩放它(但不幸的是我不能再旋转它)并在地图上拖放,但这个过程不是那么用户友好(例如,很难理解鼠标在图标上的位置,以便缩放它/拖放)。

所以我需要在我的应用程序上模拟"Photoshop Ctrl + T"行为: 因此,单击我的图标(或者可能使用组合键),它应该出现在一种矩形周围,可以让我旋转图标,编辑底部和高或按比例缩放(当然,当我完成编辑时,这个矩形应该消失)。这是可能的,如果是,我如何开发这样的东西?

这是我当前的代码:

initMap: function () {

var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
map = this.map;
this.features = new ol.Collection();

styles = [
new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.1)'
}),
}),
}),
];
var treeStyle = new ol.style.Style({
image: new ol.style.Icon({
src: 'https://www.mikenunn.net/data/oak-tree-icon-png-17.png',
}),
});
styleFunction = function(feature, resolution) {
if (feature.getGeometry().getCenter) {
treeStyle.setGeometry(new ol.geom.Point(feature.getGeometry().getCenter()));
treeStyle.getImage().setRotation(feature.getGeometry().get('rotation'));
treeStyle.getImage().setScale(feature.getGeometry().getRadius()/(150*resolution));
return treeStyle;
} else {
return styles;
}
}
featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector({
features: this.features,
wrapX: false
}),
style: styleFunction
});
featureOverlay.setMap(map);

this.draw = new ol.interaction.Draw({
features: this.features,
type: 'Circle',
geometryFunction: function(coordinates, geometry) {
var center = coordinates[0];
var last = coordinates[1];
var dx = center[0] - last[0];
var dy = center[1] - last[1];
var radius = Math.sqrt(dx * dx + dy * dy);
var rotation = Math.PI - Math.atan2(dy, dx);
geometry = geometry || new ol.geom.Circle(center, radius);
geometry.setCenter(center);
geometry.setRadius(radius);
geometry.set('rotation', rotation);
return new ol.geom.Circle(center, radius);
},
style: styleFunction,
handler: 'onSaveClick'
});
this.draw.on('drawstart', function () {
this.features.clear();
}, this);
this.map.addInteraction(this.draw);
}

添加指针移动选择交互,显示圆及其中心的样式将突出显示使用修改交互的位置

var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
var pointStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: blue
}),
stroke: new ol.style.Stroke({
color: white,
width: width / 2
})
}),
zIndex: Infinity
});
var selectStyles = [
new ol.style.Style({
fill: new ol.style.Fill({
color: [255, 255, 255, 0.5]
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: white,
width: width + 2
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: blue,
width: width
})
}),
florplanStyle,
pointStyle
];
selectStyleFunction = function(feature, resolution) {
if (feature.getGeometry().getCenter) {
pointStyle.setGeometry(new ol.geom.Point(feature.getGeometry().getCenter()));
florplanStyle.setGeometry(new ol.geom.Point(feature.getGeometry().getCenter()));
florplanStyle.getImage().setRotation(feature.getGeometry().get('rotation'));
florplanStyle.getImage().setScale(feature.getGeometry().getRadius()/(150*resolution));
return selectStyles;
} else {
return styles;
}
}
map.addInteraction(new ol.interaction.Select({
condition: ol.events.condition.pointerMove,
features: this.features,
style: selectStyleFunction
}));

将选择和绘制交互与要素集合一起使用时似乎存在问题。 它确实可以将它们链接到源

source = new ol.source.Vector({
features: this.features,
wrapX: false
}),
featureOverlay = new ol.layer.Vector({
source: source,
style: styleFunction
});
this.draw = new ol.interaction.Draw({
source: source,
type: 'Circle',
....
this.draw.on('drawstart', function () {
source.clear();
}, this);
map.addInteraction(new ol.interaction.Select({
condition: ol.events.condition.pointerMove,
source: source,
style: selectStyleFunction
}));

旋转和显示矩形几何图形需要自定义交互。 幸运的是,ol-ext 转换交互 https://viglino.github.io/ol-ext/examples/interaction/map.interaction.transform.html 似乎可以满足您的所有需求。 在使用交互之前,需要将旋转从几何移动到特征,这可以在绘图端上完成,并且样式更新为使用来自任一元素的旋转。 如果您旋转圆形功能,目前会产生奇怪的效果,我已经在代码片段中修补了该功能,但是我已经将此问题通知了 ol-ext 开发人员,因此希望如果他修复它就不需要了。

// Patch because ol-ext is changing extent of circle during rotation
ol.geom.Circle.prototype.rotate = function(){};
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
styles = [
new ol.style.Style({
fill: new ol.style.Fill({
color: [255, 255, 255, 0.5]
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: white,
width: width + 2
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: blue,
width: width
})
}),
new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: blue
}),
stroke: new ol.style.Stroke({
color: white,
width: width / 2
})
}),
zIndex: Infinity
})
];
var treeStyle = new ol.style.Style({
image: new ol.style.Icon({
src: 'https://www.freeiconspng.com/uploads/oak-tree-icon-png-17.png'
})
});
styleFunction = function(feature, resolution) {
if (feature.getGeometry().getCenter) {
treeStyle.setGeometry(new ol.geom.Point(feature.getGeometry().getCenter()));
// get rotation from drawn feature or geometry
treeStyle.getImage().setRotation(feature.get('rotation') || feature.getGeometry().get('rotation'));
treeStyle.getImage().setScale(feature.getGeometry().getRadius()/(150*resolution));
return treeStyle;
} else {
return styles;
} 
}
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var features = new ol.Collection();
var source = new ol.source.Vector({wrapX: false, features: features});
var vector = new ol.layer.Vector({
source: source,
style: styleFunction
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
var draw = new ol.interaction.Draw({
source: source,
type: 'Circle',
geometryFunction: function(coordinates, geometry) {
var center = coordinates[0];
var last = coordinates[1];
var dx = center[0] - last[0];
var dy = center[1] - last[1];
var radius = Math.sqrt(dx * dx + dy * dy);
var rotation = Math.PI - Math.atan2(dy, dx);
geometry = geometry || new ol.geom.Circle(center, radius);
geometry.setCenterAndRadius(center, radius);
geometry.set('rotation', rotation);
return geometry;
},
style: styleFunction
});
draw.on('drawstart', function () {
//source.clear();
});
draw.on('drawend', function (evt) {
// move rotation from geometry to drawn feature
evt.feature.set('rotation', evt.feature.getGeometry().get('rotation'));
evt.feature.getGeometry().unset('rotation');
});
map.addInteraction(draw);
var modify = new ol.interaction.Transform({
features: features
});
var startangle = 0;
modify.on('rotatestart', function(e) {
startangle = e.feature.get('rotation') || 0;
});
modify.on('rotating', function (e) {
// Set angle attribute to be used on style !
e.feature.set('rotation', startangle - e.angle);
});
modify.on('select', function(e) {
draw.setActive(e.features.length == 0);
});
map.addInteraction(modify);
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://viglino.github.io/ol-ext/dist/ol-ext.js"></script>
<div id="map" class="map"></div>

动态创建缩放图标的示例(显示边界多边形以帮助调试):

// Patch because ol-ext is changing extent of circle during rotation
ol.geom.Circle.prototype.rotate = function(angle, anchor){
var point = new ol.geom.Point(this.getCenter());
point.rotate(angle, anchor);
this.setCenter(point.getCoordinates());
};
var img = new Image();
img.crossOrigin = 'anonymous';
img.src = 'https://www.mikenunn.net/data/oak-tree-icon-png-17.png';
function getImage(img, scaleX, scaleY) {
var canvas = document.createElement('canvas');
var x = Math.round(img.width * scaleX);
var y = Math.round(img.height * scaleY);
canvas.width = x;
canvas.height = y;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, x, y);
var url = canvas.toDataURL();
canvas.remove();
return url;
}
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
styles = [
new ol.style.Style({
//     fill: new ol.style.Fill({
//       color: [255, 255, 255, 0.5]
//     })
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: white,
width: width + 2
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: blue,
width: width
})
}),
new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: blue
}),
stroke: new ol.style.Stroke({
color: white,
width: width / 2
})
}),
zIndex: Infinity
})
];
var treeStyle = new ol.style.Style({
image: new ol.style.Icon({
src: img.src
})
});
styleFunction = function(feature, resolution) {
var resAdjust = 150 * resolution;
var rotation = feature.get('rotation');
if (rotation !== undefined) {
var extent = feature.getGeometry().getExtent();
var coordinates = feature.getGeometry().getCoordinates()[0];
var tl = coordinates[0];
var bl = coordinates[1];
var br = coordinates[2];
var tr = coordinates[3];
var center = ol.extent.getCenter(extent);
var top = new ol.geom.LineString([tl, tr]).getClosestPoint(center);
var left = new ol.geom.LineString([tl, bl]).getClosestPoint(center);
var dx = center[0] - left[0];
var dy = center[1] - left[1];
var scaleX = Math.sqrt(dx * dx + dy * dy)/resAdjust;
var dx = top[0] - center[0];
var dy = top[1] - center[1];
var scaleY = Math.sqrt(dx * dx + dy * dy)/resAdjust;
var treeStyle2 = new ol.style.Style({
geometry: new ol.geom.Point(center),
image: new ol.style.Icon({
src: getImage(img, scaleX, scaleY),
rotation: rotation
})
});
return styles.concat([treeStyle2]);
} else if (feature.getGeometry().getCenter) {
treeStyle.setGeometry(new ol.geom.Point(feature.getGeometry().getCenter()));
// get rotation from drawn feature or geometry
treeStyle.getImage().setRotation(feature.getGeometry().get('rotation'));
treeStyle.getImage().setScale(feature.getGeometry().getRadius()/resAdjust);
return treeStyle;
} else {
return styles;
} 
}
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var features = new ol.Collection();
var source = new ol.source.Vector({wrapX: false, features: features});
var vector = new ol.layer.Vector({
source: source,
style: styleFunction
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
var draw = new ol.interaction.Draw({
source: source,
type: 'Circle',
geometryFunction: function(coordinates, geometry) {
var center = coordinates[0];
var last = coordinates[1];
var dx = center[0] - last[0];
var dy = center[1] - last[1];
var radius = Math.sqrt(dx * dx + dy * dy);
var rotation = Math.PI - Math.atan2(dy, dx);
geometry = geometry || new ol.geom.Circle(center, radius);
geometry.setCenterAndRadius(center, radius);
geometry.set('rotation', rotation);
return geometry;
},
style: styleFunction
});
draw.on('drawstart', function () {
//source.clear();
});
draw.on('drawend', function (evt) {
// move rotation from geometry to drawn feature
var rotation = evt.feature.getGeometry().get('rotation');
evt.feature.set('rotation', rotation);
var geom = ol.geom.Polygon.fromExtent(evt.feature.getGeometry().getExtent());
geom.rotate(-rotation, evt.feature.getGeometry().getCenter());
evt.feature.setGeometry(geom);
});
map.addInteraction(draw);
var modify = new ol.interaction.Transform({
features: features,
translateFeature: false,
// flip wouldn't be compatible with rotation
noFlip: true 
});
var startangle = 0;
modify.on('rotatestart', function(e) {
startangle = e.feature.get('rotation') || 0;
});
modify.on('rotating', function (e) {
// Set angle attribute to be used on style !
e.feature.set('rotation', startangle - e.angle);
});
modify.on('select', function(e) {
draw.setActive(e.features.length == 0);
});
map.addInteraction(modify);
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://viglino.github.io/ol-ext/dist/ol-ext.js"></script>
<div id="map" class="map"></div>

通过维护样式缩放图标的缓存可以提高性能,如果图标与适合原始圆圈内的多边形对齐,则"变换"交互作用更适合图标。

var debug = true;  // show bounding polygons
var img = new Image();
img.crossOrigin = 'anonymous';
img.src = 'https://www.mikenunn.net/data/oak-tree-icon-png-17.png';
var styleCache = {};
function getStyle(img, scaleX, scaleY) {
var x = Math.round(img.width * scaleX);
var y = Math.round(img.height * scaleY);
var key = img.src + ',' + x + ',' + y
var style = styleCache[key]
if (!style) {
var canvas = document.createElement('canvas');
canvas.width = x;
canvas.height = y;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, x, y);
var url = canvas.toDataURL();
canvas.remove();
var keys = Object.keys(styleCache);
if (keys.length >= 100) {
// delete an old entry to limit the cache size
delete styleCache[keys[0]];
}
var style = new ol.style.Style({
image: new ol.style.Icon({
src: url
})
});
styleCache[key] = style;
}
return style;
}
var white = [255, 255, 255, 1];
var blue = [0, 153, 255, 1];
var width = 3;
styles = [
new ol.style.Style({
//     fill: new ol.style.Fill({
//       color: [255, 255, 255, 0.5]
//     })
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: white,
width: width + 2
})
}),
new ol.style.Style({
stroke: new ol.style.Stroke({
color: blue,
width: width
})
}),
new ol.style.Style({
image: new ol.style.Circle({
radius: width * 2,
fill: new ol.style.Fill({
color: blue
}),
stroke: new ol.style.Stroke({
color: white,
width: width / 2
})
}),
zIndex: Infinity
})
];
var treeStyle = new ol.style.Style({
image: new ol.style.Icon({
src: img.src
})
});
styleFunction = function(feature, resolution) {
var resAdjust = 150 * resolution;
var rotation = feature.get('rotation');
if (rotation !== undefined) {
var extent = feature.getGeometry().getExtent();
var coordinates = feature.getGeometry().getCoordinates()[0];
var left = coordinates[0];
var bottom = coordinates[1];
var right = coordinates[2];
var top = coordinates[3];
var center = ol.extent.getCenter(extent);
var closest = new ol.geom.LineString([top, bottom]).getClosestPoint(left);
var dx = closest[0] - left[0];
var dy = closest[1] - left[1];
var scaleX = Math.sqrt(dx * dx + dy * dy)/resAdjust;
var dx = top[0] - center[0];
var dy = top[1] - center[1];
var scaleY = Math.sqrt(dx * dx + dy * dy)/resAdjust;
var rotation = Math.atan2(dx, dy) - Math.PI;
var treeStyle2 = getStyle(img, scaleX, scaleY);
treeStyle2.setGeometry(new ol.geom.Point(center));
treeStyle2.getImage().setRotation(rotation);
return debug ? styles.concat([treeStyle2]) : treeStyle2;
} else if (feature.getGeometry().getCenter) {
treeStyle.setGeometry(new ol.geom.Point(feature.getGeometry().getCenter()));
// get rotation from drawn feature or geometry
treeStyle.getImage().setRotation(feature.getGeometry().get('rotation'));
treeStyle.getImage().setScale(feature.getGeometry().getRadius()/resAdjust);
return treeStyle;
} else {
return styles;
} 
}
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var features = new ol.Collection();
var source = new ol.source.Vector({wrapX: false, features: features});
var vector = new ol.layer.Vector({
source: source,
style: styleFunction
});
var map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 4
})
});
var draw = new ol.interaction.Draw({
source: source,
type: 'Circle',
geometryFunction: function(coordinates, geometry) {
var center = coordinates[0];
var last = coordinates[1];
var dx = center[0] - last[0];
var dy = center[1] - last[1];
var radius = Math.sqrt(dx * dx + dy * dy);
var rotation = Math.PI - Math.atan2(dy, dx);
geometry = geometry || new ol.geom.Circle(center, radius);
geometry.setCenterAndRadius(center, radius);
geometry.set('rotation', rotation);
return geometry;
},
style: styleFunction
});
draw.on('drawstart', function () {
//source.clear();
});
draw.on('drawend', function (evt) {
// move rotation from geometry to drawn feature
var rotation = evt.feature.getGeometry().get('rotation');
evt.feature.set('rotation', rotation);
var geom = ol.geom.Polygon.fromCircle(evt.feature.getGeometry(), 4, -rotation);
evt.feature.setGeometry(geom);
});
map.addInteraction(draw);
var modify = new ol.interaction.Transform({
features: features,
translateFeature: false,
// flip wouldn't be compatible with rotation
noFlip: true 
});
var startangle = 0;
modify.on('rotatestart', function(e) {
startangle = e.feature.get('rotation') || 0;
});
modify.on('rotating', function (e) {
// Set angle attribute to be used on style !
e.feature.set('rotation', startangle - e.angle);
});
modify.on('select', function(e) {
draw.setActive(e.features.length == 0);
});
map.addInteraction(modify);
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://viglino.github.io/ol-ext/dist/ol-ext.js"></script>
<div id="map" class="map"></div>

最新更新