OpenLayer Icon用户自由转换

时间:2019-04-02 14:05:08

标签: javascript openlayers

在我的应用程序中,我编写了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);
        }

1 个答案:

答案 0 :(得分:1)

添加具有显示圆圈及其中心的样式的指针移动选择交互,将突出显示在何处使用修改交互

  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 Transform交互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>

通过保留样式化缩放图标的缓存来提高性能,并且如果将图标对齐到适合原始圆内的多边形,则Transform交互会更好地适合图标。

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>