首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何旋转/转换mapbox绘制功能?

如何旋转/转换mapbox绘制功能?
EN

Stack Overflow用户
提问于 2018-02-13 16:54:41
回答 1查看 2.8K关注 0票数 1

我正在使用mapbox-gl-draw为我的地图添加可移动功能。除了可移动功能之外,我还需要旋转/转换-ability功能,以实现类似于Leaflet.Path.Transform的功能。

目前,我唯一的选择是创建一个自定义模式

,例如,类似于:

代码语言:javascript
复制
map.on('load', function() {
  Draw.changeMode('transform');
});

我无法转换我的地图和它的功能到mapbox-gl-传单,以实现Leaflet.Path.Transform,因为失去旋转/轴承/节距支持不是一个选项。

EN

回答 1

Stack Overflow用户

发布于 2018-02-28 22:35:39

长话短说来了。(一些最终产品见http://mapster.me/mapbox-gl-draw-rotate-modehttp://npmjs.com/package/mapbox-gl-draw-rotate-modehttps://github.com/mapstertech/mapbox-gl-draw-rotate-mode)

我一直在为一个定制项目做类似的工作,而不是使用抽签库。我的项目涉及一些相当有规律的对象,不是非常复杂的多边形,所以解决方案可能对您来说太简单了,但它可能是正确的路径。我只有旋转和移动。

做运动在地理上并不难。这里有一些帮助让你开始。一个基本的JSBin在https://jsbin.com/yoropolewo/edit?html,output上有一些拖动功能(太累了,不能旋转)。

首先,注册必要的单击事件以具有拖放事件。您可以在特定的Mapbox层上监听鼠标向下,然后在整个文档上监听mousemove和mouseup。

要做单独的形状旋转,您需要确保您所指的是正确的功能。在本例中,我假设源数据中只有一个特性,但对于大多数用途来说,这可能太简单了,所以您必须进行推断。源数据是我们稍后setData()时影响的内容。很明显,我在这里做的事情有很多种方法,但我想说清楚。

代码语言:javascript
复制
var currentDragging = false;
var currentDraggingFeature = false;
var currentDraggingType = false;
var firstDragEvent = false;

map.on('mousedown','my-layer-id',function(e) {
    currentDragging = 'my-source-id'; // this must correspond to the source-id of the layer
    currentDraggingFeature = e.features[0]; // you may have to filter this to make sure it's the right feature
    currentDraggingType = 'move'; // rotation or move
    firstDragEvent = map.unproject([e.originalEvent.layerX,e.originalEvent.layerY]);
});
window.addEventListener('mousemove',dragEvent);
window.addEventListener('mouseup',mouseUpEvent);

那么,您需要一个函数,它需要一个初始点、一个距离和一个旋转,并将一个点返回给您。如下所示:

代码语言:javascript
复制
Number.prototype.toRad = function() {
    return this * Math.PI / 180;
}

Number.prototype.toDeg = function() {
    return this * 180 / Math.PI;
}

function getPoint(point, brng, dist) { 
    dist = dist / 63.78137; // this number depends on how you calculate the distance
    brng = brng.toRad();

    var lat1 = point.lat.toRad(), lon1 = point.lng.toRad();
    var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
                      Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));

    var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
                              Math.cos(lat1),
                              Math.cos(dist) - Math.sin(lat1) *
                              Math.sin(lat2));

    if (isNaN(lat2) || isNaN(lon2)) return null;

    return [lon2.toDeg(),lat2.toDeg()];
}

现在,关键是Mapbox中的unproject方法,因此您可以在鼠标上的x/y坐标和地图上的lng/lat之间移动。然后,使用map.getSource().setData()函数设置一个新的geoJSON。

我马上把x/y转换成坐标,但是你可以在任何时候做。类似于移动的如下内容:

代码语言:javascript
复制
function moveEvent(e) {
    // In the case of move, you are just translating the points based on distance and angle of the drag
    // Exactly how your translate your points here can depend on the shape
    var geoPoint = map.unproject([e.layerX,e.layerY]);
    var xDrag = firstDragEvent.lng - geoPoint.lng;
    var yDrag = firstDragEvent.lat - geoPoint.lat;
    var distanceDrag = Math.sqrt( xDrag*xDrag + yDrag*yDrag );
    var angle = Math.atan2(xDrag, yDrag) * 180 / Math.PI;

    // Once you have this information, you loop over the coordinate points you have and use a function to find a new point for each
    var newFeature = JSON.parse(JSON.stringify(currentDraggingFeature));
        if(newFeature.geometry.type==='Polygon') {
            var newCoordinates = [];
            newFeature.geometry.coordinates.forEach(function(coords) {
                newCoordinates.push(getPoint(coords,distanceDrag,angle));
            });
            newFeature.geometry.coordinates = newCoordinates;
        }
    map.getSource(currentDragging).setData(newFeature);
}

旋转有点困难,因为你想要形状围绕一个中心点旋转,你需要知道每个点到那个中心点的距离才能做到这一点。如果你有一个简单的正方形多边形,这个计算将很容易。如果没有,那么使用这样的东西将是有帮助的(找到小叶多边形的中心?):

代码语言:javascript
复制
var getCentroid2 = function (arr) {
    var twoTimesSignedArea = 0;
    var cxTimes6SignedArea = 0;
    var cyTimes6SignedArea = 0;

    var length = arr.length

    var x = function (i) { return arr[i % length][0] };
    var y = function (i) { return arr[i % length][1] };

    for ( var i = 0; i < arr.length; i++) {
        var twoSA = x(i)*y(i+1) - x(i+1)*y(i);
        twoTimesSignedArea += twoSA;
        cxTimes6SignedArea += (x(i) + x(i+1)) * twoSA;
        cyTimes6SignedArea += (y(i) + y(i+1)) * twoSA;
    }
    var sixSignedArea = 3 * twoTimesSignedArea;
    return [ cxTimes6SignedArea / sixSignedArea, cyTimes6SignedArea / sixSignedArea];        
}

一旦你有能力知道多边形的中心,你就是黄金:

代码语言:javascript
复制
function rotateEvent(e) {
    // In the case of rotate, we are keeping the same distance from the center but changing the angle

    var findPolygonCenter = findCenter(currentDraggingFeature);
    var geoPoint = map.unproject([e.layerX,e.layerY]);
    var xDistanceFromCenter = findPolygonCenter.lng - geoPoint.lng;
    var yDistanceFromCenter = findPolygonCenter.lat - geoPoint.lat;
    var angle = Math.atan2(xDistanceFromCenter, yDistanceFromCenter) * 180 / Math.PI;

    var newFeature = JSON.parse(JSON.stringify(currentDraggingFeature));
    if(newFeature.geometry.type==='Polygon') {
        var newCoordinates = [];
        newFeature.geometry.coordinates.forEach(function(coords) {

            var xDist = findPolygonCenter.lng - coords[0];
            var yDist = findPolygonCenter.lat - coords[1];
            var distanceFromCenter = Math.sqrt( xDist*xDist + yDist*yDist );
            var rotationFromCenter = Math.atan2(xDist, yDist) * 180 / Math.PI;
            newCoordinates.push(
                getPoint(coords,distanceFromCenter,rotationFromCenter+angle)
            );
        });
        newFeature.geometry.coordinates = newCoordinates;
    }
}

当然,在整个过程中,确保您的坐标被传递并正确地从函数返回。其中一些代码可能包含不正确的数组级别。与geoJSON数组相比,lat/lng对象很容易遇到bug。

我希望解释是简短的,但足够清楚,你应该从逻辑上理解我们正在做什么来重新定位这些观点。这就是重点,确切的代码是细节。

也许我该做个模组或者叉子。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48771838

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档