无法从画布中制作大块

时间:2018-02-24 11:36:34

标签: javascript canvas openlayers

我希望与地图进行这样的交互,当用户选择地图上的某个区域时,会从该区域创建图像。我在这个fiddle中做了一个最小化且完全可重复的例子。最重要的部分是这种作物功能:

function crop(img, sx, sy, dw, dh) {
   var canvas = document.createElement('canvas');
   var ctx = canvas.getContext('2d');
   canvas.width = dw;
   canvas.height = dh;
   ctx.drawImage(img, sx, sy, dw, dh, 0, 0, dw, dh);
   return canvas.toDataURL("image/png");
}

此功能从选定区域创建一个块。选择的方式如下:

enter image description here

但这就是我得到的结果:

enter image description here

所以,我的大块是完全错误的。但更有趣的是,在某些任意计算机和某些任意浏览器中,块是正确的。所以,我真的需要让这个代码跨平台和跨浏览器。

2 个答案:

答案 0 :(得分:2)

  

但问题是,似乎从JavaScript代码中不可能知道这个系统/浏览器参数 - 我的意思是初始页面缩放级别。

实际上有window.devicePixelRatio
只需使用它代替ratio_Wratio_H,它就会开始工作:



var initialZoom = devicePixelRatio;

var map = new ol.Map({
  layers: [new ol.layer.Tile({
    source: new ol.source.OSM()
  })],
  target: 'map',
  view: new ol.View({
    center: [-348792.96, 7170957.18],
    zoom: 10
  })
});

var draw = new ol.interaction.Draw({
   features: new ol.Collection(),
   type: "LineString",
   style: function (feature) {
       var style = [
         new ol.style.Style({
           fill: new ol.style.Fill({
             color: 'rgba(142,142,142,0.5)'
           }),
           stroke: new ol.style.Stroke({
             color: 'rgba(142,142,142,1)',
             lineDash: [4,4],
             width: 2
           })
         })
       ];
       return style;
   },
   geometryFunction: function (coordinates, geom) {
       if (!geom) {
           geom = new ol.geom.Polygon(null);
       }
       var start = coordinates[0];
       var end = coordinates[1];
       var mapExtent = map.getView().calculateExtent(map.getSize());

       var chunk = [start, [start[0], end[1]], end, [end[0], start[1]],start];
       var coords = [[[mapExtent[0],mapExtent[1]],[mapExtent[0],mapExtent[3]],[mapExtent[2],mapExtent[3]],[mapExtent[2],mapExtent[1]],[mapExtent[0],mapExtent[1]]], chunk];
       map.exportExtent = coordinates; // all you need
       geom.setCoordinates(coords);
       return geom;
   },
   maxPoints: 2
});

var canvas = map.getViewport().firstChild;

draw.on("drawend", function (e) {
    var image = new Image(), 
        link = document.getElementById("export-png");
   
    var topLeft = map.getPixelFromCoordinate(map.exportExtent[0]);
    var bottomRight = map.getPixelFromCoordinate(map.exportExtent[1]);
    
    var sx = topLeft[0];
    var sy = topLeft[1];
    var dw = bottomRight[0] - topLeft[0];
    var dh = bottomRight[1] - topLeft[1];
    
    image.id = "pic";
    image.crossOrigin = "anonymous";
    image.onload = function () { 
        sx = sx * initialZoom;
        sy = sy * initialZoom;
        dw = dw * initialZoom;
        dh = dh * initialZoom;
        link.href = crop(image, sx, sy, dw, dh);
        link.click();
    };
    
    image.src = canvas.toDataURL("image/png");
});

map.addInteraction(draw);

function crop(img, sx, sy, dw, dh) {
   var canvas = document.createElement('canvas');
   var ctx = canvas.getContext('2d');
   canvas.width = dw;
   canvas.height = dh;
   ctx.drawImage(img, sx, sy, dw, dh, 0, 0, dw, dh);
   return canvas.toDataURL("image/png");
}

<link href="https://openlayers.org/en/v4.6.4/css/ol.css" rel="stylesheet"/>
<script src="https://openlayers.org/en/v4.6.4/build/ol-debug.js"></script>
<div id="map" class="map"></div> 
<a id="export-png" class="btn" download="map.png">&nbsp;</a>
&#13;
&#13;
&#13;

Snippet来自@ dube的回答,我修改了image.onload 并在第一行存储了initialZoom

答案 1 :(得分:1)

我猜想你混合了预测。但这不是错误,你只是混淆了一些变量。这是存储选择范围的不必要的复杂方式。

coordinate的{​​{1}}已经具有范围,定义为两个坐标。只需使用它们并删除循环。不知道为什么它首先出现在那里。

geometryFunction
var map = new ol.Map({
  layers: [new ol.layer.Tile({
    source: new ol.source.OSM()
  })],
  target: 'map',
  view: new ol.View({
    center: [-348792.96, 7170957.18],
    zoom: 10
  })
});

var draw = new ol.interaction.Draw({
   features: new ol.Collection(),
   type: "LineString",
   style: function (feature) {
       var style = [
         new ol.style.Style({
           fill: new ol.style.Fill({
             color: 'rgba(142,142,142,0.5)'
           }),
           stroke: new ol.style.Stroke({
             color: 'rgba(142,142,142,1)',
             lineDash: [4,4],
             width: 2
           })
         })
       ];
       return style;
   },
   geometryFunction: function (coordinates, geom) {
       if (!geom) {
           geom = new ol.geom.Polygon(null);
       }
       var start = coordinates[0];
       var end = coordinates[1];
       var mapExtent = map.getView().calculateExtent(map.getSize());

       var chunk = [start, [start[0], end[1]], end, [end[0], start[1]],start];
       var coords = [[[mapExtent[0],mapExtent[1]],[mapExtent[0],mapExtent[3]],[mapExtent[2],mapExtent[3]],[mapExtent[2],mapExtent[1]],[mapExtent[0],mapExtent[1]]], chunk];
       map.exportExtent = coordinates; // all you need
       geom.setCoordinates(coords);
       return geom;
   },
   maxPoints: 2
});

var canvas = map.getViewport().firstChild;

draw.on("drawend", function (e) {
    var image = new Image(), 
        link = document.getElementById("export-png");
   
    var topLeft = map.getPixelFromCoordinate(map.exportExtent[0]);
    var bottomRight = map.getPixelFromCoordinate(map.exportExtent[1]);
    
    var sx = topLeft[0];
    var sy = topLeft[1];
    var dw = bottomRight[0] - topLeft[0];
    var dh = bottomRight[1] - topLeft[1];
    
    image.id = "pic";
    image.crossOrigin = "anonymous";
    image.onload = function () { 
        var ratio_W = canvas.clientWidth / image.naturalWidth;
        var ratio_H = canvas.clientHeight / image.naturalHeight;
        //with or without scaling image chunk is incorrect
        sx = sx * ratio_W;
        sy = sy * ratio_H;
        dw = dw * ratio_W;
        dh = dh * ratio_H;
        // console.log(sx, sy, dw, dh, ratio_H);
        link.href = crop(image, sx, sy, dw, dh);
        link.click();
    };
    
    image.src = canvas.toDataURL("image/png");
});

map.addInteraction(draw);

function crop(img, sx, sy, dw, dh) {
   var canvas = document.createElement('canvas');
   var ctx = canvas.getContext('2d');
   canvas.width = dw;
   canvas.height = dh;
   ctx.drawImage(img, sx, sy, dw, dh, 0, 0, dw, dh);
   return canvas.toDataURL("image/png");
}