一、问题来源:

接触Openlayers 一段时间了,最近做了一个农业产业系统,项目中涉及到产业图例,最后考虑用canvas来绘制图例图像。当中带图片的图例移动时,图片会实现闪烁留白情况。闪烁是因为绘制图片本身的复杂性,导致canvas绘制频率和浏览器绘制频率不同步,出现图片出不来或者延迟出现,这过程中间就出现了空白显示为canvas底图颜色白色的情况。这里说的闪烁是,在单击地图移动图例时,文字前面的图片并没有出来。但是单击地图准备移动图例时别松开鼠标图片能出来,这个有点奇怪....

有些解决方案是用一个叫双缓冲的技术实现,这种办法确实能行,这里就不写了,用我们的办法实现。

双缓冲实现原理:创建一个临时canvas,先把下一帧动画绘制到临时canvas上。在每次真正绘制的时候,擦除正式canvas后,马上drawImage把临时canvas的内容copy过去,而这个copy过程是非常非常高效的,所以基本可以杜绝闪烁。

二 、实现步骤

1、new一个layer层,new一个Feature要素。

2、绘制一个canvas图像。

3、new一个样式,设置样式的Icon图片为上一步绘制好的canvas,并设置Icon宽高为canvas宽高。

4、设置要素Feature的样式为上一步new的样式,将要素Feature添加到layer层上。

5、最后将layer层添加到地图中。

三、加载ol地图,加载天地图矢量图为底图

      <script type="text/javascript">
var projection = ol.proj.get('EPSG:4326');
var projectionExtent = projection.getExtent();
var size = ol.extent.getWidth(projectionExtent) / ;
var resolutions = new Array(),
matrixIds = new Array(),
shapeArr = [];
for(var z = ; z <= ; ++z) {
resolutions[z] = size / Math.pow(, z);
matrixIds[z] = z;
}
//天地图矢量图
var tdt_road_layer = new ol.layer.Tile({
name: '矢量底图',
source: new ol.source.WMTS({
url: 'http://t1.tianditu.com/vec_c/wmts',
layer: 'vec',
matrixSet: 'c',
format: 'tiles',
projection: projection,
tileGrid: new ol.tilegrid.WMTS({
origin: ol.extent.getTopLeft(projectionExtent),
resolutions: resolutions,
matrixIds: matrixIds
}),
style: 'default'
}),
visible: true,
zIndex:
});
var view = new ol.View({
center: [118.77, 32.05],
zoom: 9.5,
projection: "EPSG:4326",
maxZoom:
});
var map = new ol.Map({
// 设置地图控件,默认的三个控件都不显示
controls: ol.control.defaults({
attribution: true,
rotate: true,
zoom: true
}).extend([
new ol.control.FullScreen(),
new ol.control.ScaleLine()
]),
layers: [
tdt_road_layer
],
target: 'map',
loadTilesWhileAnimating: true,
view: view
});
      </script>

四、实现代码,实现文字前面带图片和带色块图例,有背景色的代码为方法调用,调用即可

      <script type="text/javascript">
          window.onload = function() {
getMapPoint();
drawMapTuliMethod();
}
/*
* 图例数据
*/
var dataObj = [{
tname: '国家级文物保护建筑',
color: '#365e96',
}, {
tname: '省级文物保护建筑',
color: '#d1702f',
}, {
tname: '市级级文物保护建筑',
color: '#4fa1dc',
}, {
tname: '区县级文物保护建筑',
color: '#368829',
}]
/*
* 图例经纬度坐标,地图绑定了单击事件
* 单击返回经纬度并重新绘制canvas
*/
var removeData = {
tx: 118.82368355230953,
ty: 32.2359887979324
}
var canvas = document.createElement('canvas'); //绘制图例
function drawMapTuliMethod() {
var layers = new ol.layer.Vector({
type: 'tuli',
source: new ol.source.Vector(),
zIndex:
})
var shape = new ol.Feature({
geometry: new ol.geom.Point([removeData.tx, removeData.ty])
}); var ctx = canvas.getContext("2d");
var yheight = ;
yheight += dataObj.length * ; //计算canvas高度
canvas.width = ;
canvas.height = yheight; /*设置图例样式*/
ctx.fillStyle = "#fff";
ctx.fillRect(, , , yheight); //绘制底图
ctx.font = "16px Arial";
ctx.fillStyle = "#000";
ctx.fillText('图例', canvas.width / 2.5, );
for(var i = ; i < dataObj.length; i++) {
//实现文字前面带色块
//ctx.fillStyle = dataObj[i].color; //块颜色
//ctx.fillRect(10, 60 + (i - 1) * 25, 15, 15); //颜色块:x,y,w,h ctx.font = "12px Arial";
ctx.fillStyle = "#555";
ctx.fillText(dataObj[i].tname, , + (i - ) * ); //文字 //添加图片方法一,实现文字前面带图片,移动图例不会出现闪烁
drawImg_first('xiushan.png', i); //添加图片方法二,移动图例会出现闪烁
//drawImg_Second(ctx, 'xiushan.png', i);
}
//将canvas添加到样式中
var style = new ol.style.Style({
image: new ol.style.Icon({
img: canvas,
imgSize: [canvas.width, canvas.height],
})
});
shape.setStyle(style);
layers.getSource().addFeature(shape);
map.addLayer(layers);
} /*
* 将绘制完成的图片添加到canvas上
* @imgObj:图片对象
* @p:循环序号,确定图片坐标
*/
function drawTuliImage(imgObj, p) {
var ctxImge = canvas.getContext("2d");
ctxImge.drawImage(imgObj, , + (p * ), , );
} /*
* 绘制图例上的图片,方法一
* 此方法能解决重绘canvas时图片闪烁留白的问题
* @imgs:图片名称
* @p:序号
* @complete:HTMLImageElement对象的一个属性,可以判断图片加载完成
*/
function drawImg_first(imgs, p) {
var imgObj = new Image();
imgObj.src = 'img/' + imgs;
//如果图片加载完成
if(imgObj.complete) {
drawTuliImage(imgObj, p);
} else {
//onload:重绘,重新加载
imgObj.onload = function() {
drawTuliImage(imgObj, p);
};
//加载失败
imgObj.onerror = function() {
console.log('canvas图片加载失败,请重试!')
};
}
} /*
* 添加数据前面的图片,方法二
* 此方法绘制图片会出现闪烁留白情况,
* @ctx:绘图环境
* @imgs:图片名称
* @p:循环序号
*/
function drawImg_Second(ctx, imgs, p) {
var imgObj = new Image();
imgObj.src = 'img/' + imgs;
imgObj.onload = function() {
ctx.drawImage(imgObj, , + (p * ), , );
}
} /*
* 添加图例之前删除原来
* 引用类型。length会变化,for循环倒着删除
* @deType:要删除的覆盖物名称
*/
function addNewsChartsDelectOring(deType) {
var layersArr = map.getLayers().getArray(); //获取所有覆盖物
//移除全部
if(deType == 'all') {
for(var i = layersArr.length - ; i >= ; i--) {
var ltype = layersArr[i].get('type');
if(ltype == 'tuli') map.removeLayer(layersArr[i]);
}
return;
}
//移除具体
else {
for(var i = layersArr.length - ; i >= ; i--) {
var ltype = layersArr[i].get('type');
if(ltype == deType) map.removeLayer(layersArr[i]);
}
return;
}
} //地图单击事件
function getMapPoint() {
map.on('click', function(evt) {
var point = evt.coordinate; //鼠标单击点坐标
removeData.tx = point[];
removeData.ty = point[];
addNewsChartsDelectOring('all');
drawMapTuliMethod();
});
}
</script>

①文字前面带图片的图例,移动图例时canvas绘制图片频率和浏览器绘制频率不一导致图片不出来的效果图:

②文字前面带图片的效果图:

③文字前面带色块的效果图:

技术群 : 192713488

openLayers 4 canvas图例绘制,canvas循环添加图片,解决图片闪烁问题的更多相关文章

  1. Android 如何将Canvas上绘制的内容保存成本地图片(转)

    效果如下图所示 保存在sd卡上的文件为 手机上显示效果为: 1>>在Manifest文件中增加相应权限 <!-- 在SDCard中创建与删除文件权限 --> <uses- ...

  2. canvas纯绘制雨伞、飞机、五角星、桃心,无逻辑

    由于网上很多都是用很多算法和逻辑使用canvas进行绘制,但有时也无法解决一些小众需求 . 为了满足需求不能写运算纯手写,感觉真的很浪费时间,只有自己踩过的坑,才不想看到别人也被坑.我很懒,也想过弄个 ...

  3. canvas高效绘制10万图形,你必须知道的高效绘制技巧

    最近的一个客户项目中,简化的需求是绘制按照行列绘制很多个圆圈.需求看起来不难,上手就可以做,写两个for循环. 原始绘制方法 首先定义了很多Circle对象,在遍历循环中调用该对象的draw方法.代码 ...

  4. HTML5 Canvas中绘制椭圆的几种方法

    1.canvas自带的绘制椭圆的方法 ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)是后来 ...

  5. HTML5使用Canvas来绘制图形

    一.Canvas标签: 1.HTML5<canvas>元素用于图形的绘制,通过脚本(通常是javascript)来完成. 2.<canvas>标签只是图形容器,必须使用脚本来绘 ...

  6. Canvas 实现绘制图表

    这里用canvas实现了两个简单的图表,用到了canvas的基本用法,效果如下 新建 chart.js 文件,封装绘制方法 构造方法 function myChart(config){ this.wi ...

  7. canvas+js绘制序列帧动画+面向对象

    效果: 素材: 源码:(一般的绘制方式) <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  8. 软件项目技术点(7)——在canvas上绘制自定义图形

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 图形种类 目前我们软件可以绘制出来的形状有如下这几种,作为开发者我们一直想支持用户可以拖拽的类似word里面图形库,但目前还没有找到比 ...

  9. Canvas:绘制路径

    Canvas:绘制路径 绘制路径 图形的基本元素是路径.路径是[通过不同颜色和宽度的线段或曲线相连形成的不同形状的]点的集合.一个路径,甚至一个子路径,都是闭合的. 使用路径绘制图形需要一些额外的步骤 ...

随机推荐

  1. SPP Net(Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition)论文理解

    论文地址:https://arxiv.org/pdf/1406.4729.pdf 论文翻译请移步:http://www.dengfanxin.cn/?p=403 一.背景: 传统的CNN要求输入图像尺 ...

  2. English trip -- VC(情景课)1 A Get ready

    Meet your classmates 见见你的同学 Look at the picture. What do you see? 看图片.你看到了什么? calendar  日历 bookcase ...

  3. 20170709pptVBA递归删除LOGO图片与文字

    Public Sub StartRecursionFolder() Dim Pre As Presentation Dim FolderPath As String Dim pp As String ...

  4. Android之封装好的异步网络请求框架

    1.简介  Android中网络请求一般使用Apache HTTP Client或者采用HttpURLConnection,但是直接使用这两个类库需要写大量的代码才能完成网络post和get请求,而使 ...

  5. Confluence 6 的 Crowd 权限

    只读(Read Only) 从 Crowd 上获取的用户,用户组和用户组成员信息只具有读取权限,你只能在 Crowd 上对你的配置进行修改.你不能通过你的应用程序管理员界面修改,用户,用户组,用足成员 ...

  6. 『Kaggle』分类任务_决策树&集成模型&DataFrame向量化操作

    决策树这节中涉及到了很多pandas中的新的函数用法等,所以我单拿出来详细的理解一下这些pandas处理过程,进一步理解pandas背后的数据处理的手段原理. 决策树程序 数据载入 pd.read_c ...

  7. python-day6---运算符

    #了解部分#字符串+,*#列表:+,*# l1=[1,2,3]# l2=[4,5]## print(l1+l2)# print(l1*3) #比较运算符# num1=3# num2=1 # print ...

  8. 最齐全的Android studio 快捷键(亲测可用)

    Action Mac OSX Win/Linux 注释代码(//) Cmd + / Ctrl + / 注释代码(/**/) Cmd + Option + / Ctrl + Alt + / 格式化代码 ...

  9. Application 类

    Application 类具有用于启动和停止应用程序和线程以及处理 Windows 消息的方法,如下所示: Run 在当前线程上启动应用程序消息循环,并可以选择使某窗体可见. Exit 或 ExitT ...

  10. OC 内存管理之手动内存管理MRC

    一.基本原理 1.什么是内存管理 内存管理的重要性: 移动设备的内存极其有限,每个app所能占用的内存是有限制的 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间. ...