技术要点:

  1.img 绘制到canvas

  2.绘制完成以后进行拖拽,缩放

  3.使用canvas画图,在绘制的img上进行标记划线,当然可以实现跟过功能,例如百度地图的功能,做单个标记,区域标记等。

  4.实现坐标等转换,标记区域的所有坐标都是基于相对原始图片的坐标,便于其他操作。

实际项目中的开发实现效果截图如下:

点击边界标记,就可以开始左键划线功能,会自动形成闭合区域,点击右键结束划线。同时可以删除当前绘制的区域。

  

区域标记完成以后,就可以进行设备的选择,设备从左侧列表点击以后,放到右侧canvas 的区域,放下后还可以继续拖拽改变其位置,而且保持对应关系。

这些标记区域和标记点都可以基于底图的缩放和拖拽进行位置的等比例渲染,但是保存的坐标始终是基于原图的。

部分效果源码,本地看的话需要给img 图片路径,正确的路径。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>标记</title>
</head>
<style>
html, body {
height: 100%;
min-height: 100%;
overflow: hidden;
} * {
margin: 0;
padding: 0;
box-sizing: border-box;
border:none;
} .canvasWrap {
width: 100%;
height: 100%;
background: #ccc;
}
.mark_list{
position: absolute;
top: 20px;
right: 10px; }
.mark_list li{
float: left;
width: 100px;
border-radius: 4px;
border: 1px solid #ccc;
list-style: none;
line-height: 30px;
text-align: center;
color:#333;
background: #fff;
cursor: pointer;
}
.mark_list li:hover{
background: #009a8f;
color:#fff;
}
</style>
<body> <div class="canvasWrap" id="wrap">
<canvas id="draw"> </canvas> <ul class="mark_list">
<li class="border_mark">标记区域</li>
<li>标记点位</li>
</ul>
</div> </body>
<script>
function MarkPoints(Imgurl) {
this.imgX = 0;//在画布上图片的X偏移量
this.imgY = 0;//在画布上图片的Y偏移量
this.imgScale = 1;//图片的缩放比例
this.rateNum;//图片高度自适应比例,图片等比居中展示在canvas
this.scaleFlag = 0;//缩放因子,最大缩放9,最小缩放-9
this.context;
this.img;
this.pos={};//每次拖拽前坐标保存
this.dragFlag=false;//是否可拖拽当前img,默认不能
this.markFlag=false;//标记区域开启关闭flag
this.CreatLinepoints = [];//每次创建新区域的坐标集合
this.allMarkLins = [];//已创建的区域集合,例如[[{x,y},{x,y},{x,y}],[{n,m},{n,m},{n,m}]]目前只需要一个区域,所以数组内部只有一项
this.getImgLoad(Imgurl);
this.init();
document.oncontextmenu = new Function("event.returnValue=false;");
document.onselectstart = new Function("event.returnValue=false;"); } MarkPoints.prototype = {
getImgLoad: function (Imgurl) {
var _this = this;
var wrap = document.getElementById('wrap');
_this.canvas = document.getElementById('draw');
_this.context = draw.getContext('2d');
_this.canvas.height = wrap.offsetHeight;
_this.canvas.width = wrap.offsetWidth;
_this.img = new Image();
_this.img.onload = function () {
_this.imgX = 0;
_this.imgY = 0;
_this.imgScale = 1;
_this.imgScale=_this.rateNum = _this.canvas.height / _this.img.naturalHeight;
_this.imgX = (_this.canvas.width - _this.img.naturalWidth * _this.imgScale * _this.rateNum) / 2;//默认进来当前图像剧中显示
/*画出当前图片*/
_this.drawImg();
}
_this.img.src = imgUrl; },
getNewPoints: function (points) {
var _this=this;
var newPointAry = [];
for (var i = 0; i < points.length; i++) {
var obj = {};
obj.x = points[i].x * _this.imgScale + _this.imgX;
obj.y = points[i].y * _this.imgScale + _this.imgY;
if (points[i].hasOwnProperty('mac')) {
obj.mac = points[i].mac;
obj.name = points[i].name || '';
} newPointAry.push(obj);
}
return newPointAry;
},
drawImg: function () {
var _this = this;
_this.context.clearRect(0, 0, _this.canvas.width, _this.canvas.height);
_this.context.drawImage(_this.img, 0, 0, _this.img.naturalWidth, _this.img.naturalHeight, _this.imgX, _this.imgY, _this.img.naturalWidth * _this.imgScale * _this.rateNum, _this.img.naturalHeight * _this.imgScale * _this.rateNum);
if ( _this.allMarkLins.length) {
for (var m = 0; m < _this.allMarkLins.length; m++) {
var points = _this.allMarkLins[m];
var newPoints = _this.getNewPoints(points);
for (var i = 0; i < newPoints.length; i++) {
var can = _this.context;
can.beginPath();
can.arc(newPoints[i].x, newPoints[i].y, 6, 0, Math.PI * 2, true);
can.fillStyle = "#FF423E";
can.fill();
can.strokeStyle = "#FFF";
can.stroke();//画空心圆
can.closePath(); if (points.length >= 2 && i >= 1) {
can.strokeStyle = "#FF423E";
can.lineWidth = 2;
can.beginPath();
can.moveTo(newPoints[i - 1].x, newPoints[i - 1].y);
can.lineTo(newPoints[i].x, newPoints[i].y);
can.fillStyle = "#ff0000";
can.fill();
can.stroke();
can.closePath();
}
}
if (points.length >= 3) {
can.strokeStyle = "#FF423E";
can.lineWidth = 2;
can.beginPath();
can.moveTo(newPoints[newPoints.length - 1].x, newPoints[newPoints.length - 1].y);
can.lineTo(newPoints[0].x, newPoints[0].y);
can.stroke();
can.closePath();
}
}
;
} },
init:function () {
var _this=this;
_this.canvas.onmousedown=function(event){
_this.clickDown(event);
};
_this.canvas.onmousemove=function(event){
_this.mouseMove(event)
};
_this.canvas.onmouseup=function (event) {
_this.mouseUp(event);
}
_this.canvas.onmousewheel=function (event) {
_this.onmouseWheel(event);
}
document.getElementsByClassName('border_mark')[0].onclick=function () {
_this.MarkBorderline();
}
},
/*计算当前鼠标位置距离canvas的偏移量*/
xyToCanvas:function(ele,x,y){
var _this=this;
var obj = _this.canvas.getBoundingClientRect();
return {
x: x - obj.left,
y: y - obj.top
};
},
/*鼠标单击事件*/
clickDown:function(event){
var _this=this;
if (_this.markFlag) {
_this.canvas.style.cursor = "none";
if (event.button == 2) {
_this.markFlag = false;
_this.dragFlag = true;
_this.canvas.style.cursor = "normal";
_this.drawImg();
return;
} else {
var posXY = _this.xyToCanvas(_this.canvas, event.clientX, event.clientY);
posXY.x = (posXY.x - _this.imgX) / _this.imgScale;
posXY.y = (posXY.y - _this.imgY) / _this.imgScale;
_this.CreatLinepoints.push(posXY);
_this.allMarkLins.pop();
_this.allMarkLins.push(_this.CreatLinepoints);
_this.drawImg();
}
return;
}
if ( event.button == 0) {//点击鼠标左键
_this.dragFlag = true;
_this.canvas.style.cursor = "move";
_this.pos = _this.xyToCanvas(_this.canvas, event.clientX, event.clientY);
}
},
/*鼠标移动事件*/
mouseMove:function(event){
var _this=this;
/*拖拽*/
if (_this.dragFlag) {
_this.canvas.style.cursor = "move";
var pos1 = _this.xyToCanvas( _this.canvas, event.clientX, event.clientY);
var x = pos1.x - _this.pos.x;
var y = pos1.y - _this.pos.y;
_this.pos = pos1;
_this.imgX += x;
_this.imgY += y;
_this.drawImg();
}
/*边界标记*/
if (!_this.dragFlag&& _this.markFlag) {
var pos1 = _this.xyToCanvas(_this.canvas, event.clientX, event.clientY); var can = _this.context;
can.clearRect(0, 0, _this.canvas.width, _this.canvas.height);
_this.drawImg();
/*画跟随圆点*/
can.beginPath();
// can.fillText('[' + point.x + ', ' + point.y + ']', 15, 25 * (points.length + 1))
can.arc(pos1.x, pos1.y, 6, 0, Math.PI * 2, true);
can.fillStyle = "#FF423E";
can.fill();
can.strokeStyle = "#FFF";
can.stroke();//画空心圆
can.closePath(); /*当前的坐标未结束那么继续 跟随直线*/
if (!_this.CreatLinepoints.length) return;
can.strokeStyle = "red";
can.beginPath();
can.moveTo(_this.CreatLinepoints[_this.CreatLinepoints.length - 1].x * _this.imgScale + _this.imgX, _this.CreatLinepoints[_this.CreatLinepoints.length - 1].y * _this.imgScale + _this.imgY);
can.lineTo(pos1.x, pos1.y);
can.stroke();
can.closePath();
}
},
/*鼠标放开事件*/
mouseUp:function (event) {
var _this=this;
_this.dragFlag=false;
if (_this.markFlag) {
_this.canvas.style.cursor = "none";
return;
}
_this.canvas.style.cursor='default'; },
/*鼠标滚轮事件*/
onmouseWheel:function(event){
var _this=this;
var pos =_this.xyToCanvas(_this.canvas, event.clientX, event.clientY);
event.wheelDelta = event.wheelDelta ? event.wheelDelta : (event.deltaY * (-40));
if (event.wheelDelta > 0 && _this.scaleFlag < 9) {
_this.imgScale *= 2;
_this.imgX = _this.imgX * 2 - pos.x;
_this.imgY = _this.imgY * 2 - pos.y;
_this.scaleFlag += 1;
}
if (event.wheelDelta < 0 && _this.scaleFlag > -9) {//缩小
_this.imgScale *= 0.5;
_this.imgX = _this.imgX * 0.5 + pos.x * 0.5;
_this.imgY = _this.imgY * 0.5 + pos.y * 0.5;
_this.scaleFlag -= 1;
}
_this.drawImg();
},
/*边界标记*/
MarkBorderline: function () {
var _this=this;
_this.markFlag = true;//切换为true,禁止拖拽,只能标记
_this.canvas.style.cursor = "none";
_this.CreatLinepoints = [];
_this.allMarkLins.push([]);
},
/*删除标记区域*/
deleteArea: function (id) {
var _this = this;
_this.allMarkLins.splice(id, 1);
_this.drawImg();
}, }
var imgUrl = 'img/girl.jpg';//图片路径
new MarkPoints(imgUrl); </script>
</html>

基于canvas绘图 缩放 做标记的更多相关文章

  1. Canvas绘图之平移translate、旋转rotate、缩放scale

    画布操作介绍 画布绘图的环境通过translate(),scale(),rotate(), setTransform()和transform()来改变,它们会对画布的变换矩阵产生影响. 函数 方法 描 ...

  2. HTML5 学习总结(四)——canvas绘图、WebGL、SVG

    一.Canvas canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3D图像技术.<canvas> 标记和 ...

  3. canvas绘图、WebGL、SVG

    目录 一.Canvas 1.1.创建canvas元素 1.2.画线 1.3.绘制矩形 1.4.绘制圆弧 1.5.绘制图像 1.6.绘制文字 1.7.随机颜色与简单动画 二.WebGL 2.1.HTML ...

  4. HTML5 学习笔记(四)——canvas绘图、WebGL、SVG

    一.Canvas canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3D图像技术.<canvas> 标记和 ...

  5. WindowsPhone开发—— 使用手绘图片做景区导览地图

    前些日子在做景区App遇到需求,使用手绘图片做一个简易的地图,支持放大缩小平移以及显示景点Mark,安卓上可以使用一个叫做“mAppWidget”的开源库来完成,WP上有人建议用ArcGIS,但是考虑 ...

  6. HTML学习总结(四)【canvas绘图、WebGL、SVG】

    一.Canvas canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3D图像技术.<canvas> 标记和 ...

  7. Android中Canvas绘图基础详解(附源码下载) (转)

    Android中Canvas绘图基础详解(附源码下载) 原文链接  http://blog.csdn.net/iispring/article/details/49770651   AndroidCa ...

  8. HTML5 Canvas绘图如何使用

    --------------复制而来--原地址http://jingyan.baidu.com/article/ed15cb1b2e642a1be369813e.html HTML5 Canvas绘图 ...

  9. canvas绘图API详解

    canvas绘图API详解 1.context的状态 矩阵变换属性 当前剪辑区域 context的其他状态属性: strokeStyle, fillStyle, globalAlpha, lineWi ...

随机推荐

  1. 数据解析,懒加载,代理ip

    在前面的requests流程中,还缺少了一步重要的流程,就是在持久化存储之前需要进行制定的数据解析.因为在大多数情况下,我们都会使用聚焦爬虫,也就是爬取页面中的指定部分数据值,而不是整个页面的数据. ...

  2. Swift 烧脑体操(一) - Optional 的嵌套

    前言 Swift 其实比 Objective-C 复杂很多,相对于出生于上世纪 80 年代的 Objective-C 来说,Swift 融入了大量新特性.这也使得我们学习掌握这门语言变得相对来说更加困 ...

  3. 计算机网络: IP地址,子网掩码,网段表示法,默认网关,DNS服务器详解

    楔子: 以Windows系统中IP地址设置界面为参考(如图1), IP地址, 子网掩码, 默认网关 和 DNS服务器, 这些都是什么意思呢? 学习IP地址的相关知识时还会遇到网络地址,广播地址,子网等 ...

  4. Visual Studio "无法查找或打开PDB文件"解决方法

       1.问题: 使用C#语言时遇到的问题(C/C++类似,方法一致),我用qt和VS2013也遇到这种问题 编译链接都没问题,调试时出现以下错误提示:      2.解决方法 第一步: 第二步:[调 ...

  5. ios图片瀑布流代码

    ios瀑布流,实现简单的瀑布流视图布局,可以显示网络图片,下拉刷新,上拉加载更多. 下载:http://www.huiyi8.com/sc/9087.html

  6. 详解C/C++ 编译 g++ gcc 的区别

    我们在编译c/c++代码的时候,有人用gcc,有人用g++,于是各种说法都来了,譬如c代码用gcc,而c++代码用g++, 或者说编译用gcc,链 接用g++,一时也不知哪个说法正确,如果再遇上个ex ...

  7. java-01

    二,八,十六进制到十进制的转换方法: 十进制到二,八,十六进制的转换方法: 2:标识符(掌握) (1)就是给类,接口,方法,变量等起名字的字符序列 (2)组成规则: A:英文大小写字母 B:数字 C: ...

  8. UOJ_407_【IOI2018】狼人

    http://uoj.ac/problem/407 分析: 分别建立最小/最大kruskal重构树. 每次询问给出的两个点能走到的部分分别对应两棵树\(dfs\)序的一段区间. 转化成判断矩形中是否有 ...

  9. 创建maven多模块项目

    一:创建父项目

  10. P1955 [NOI2015]程序自动分析[离散化+并查集]

    大水题一道,不明白为什么你谷评了个蓝.一看就是离散化,先去满足相等的条件,相等即为两点联通,或者说在同一个集合内.再看不相等,只有两元素在同一集合才不满足.裸的disjoint-set直接上,常数巨大 ...