目前的工作在做在线的标注工具,接触canvas一年了,各种绘制,基本上图像的交互canvas都可以完成,也写了几篇关于canvas的文章,遇到的问题也写博客上了,对于canvas有问题的朋友可以去看看。一直想写一个关于canvas系列的东西,也没时间。正好最近再捣鼓canvas,有时间就写一点,一个功能一个功能的写,争取写一个系列。

以前都是绘制矩形,今天写一个新鲜的,绘制多边形可拖动编辑的多边形。见下图(截取自工程的一部分):

(太大的GIF图传不上来,只能截取一小部分,找个时间把完整的功能录一个视频放在网盘上)。

鼠标点击绘制点,并且自动绘制曲线,(当曲线闭合的时候,弹出名称边界框--不重要),绘制完毕后,点击点可以改变形状,点击曲线内部可以拖动位置。

这篇文章就先写绘制不规则图像与拖动点吧,移动图像值得另起写一篇文章。

正文

写了这么多的canvas代码,我的经验就是一定要去写,一边写边看效果,做的过程中会有新的想法。对于canvas各种绘制的效果,还是得去动手去修改才能出效果。

写之前整理下思路:

1.鼠标点击绘制点-->绘制圆的方法,鼠标点为中心点。

2.每点击一次,绘制线段。--Lineto方法。

3.判断是否闭合。

4.判断是否点击了绘制过的点上--拖动改变形状。

5.重绘。

 

     画布上每一次的更改都是要重新绘制画布的,所以要把绘制的点保存起来。这个思路和画矩形的思路大体相近,可以看下我的绘制矩形的文章

  1. //线段的点的集合
  2. var points=[];
  3. //可拖动圆圈的点的集合
  4. var circles=[];
  5. //每一个点的对象
  6. function Point(x, y) {
  7. this.x = x;
  8. this.y = y;
  9. }
  10. //圆圈对象
  11. function Circle(x, y) {
  12. this.x = x;
  13. this.y = y;
  14. this.radius = 10;
  15. this.color = "blue";
  16. //拖拽点的标记
  17. this.isSelected = false;
  18. }
  19. /*每一次的点都看作一个对象,然后把点放在数组里保存起来
  20. 这样circles和points就会是这种形式
  21. points=[{(x0,y0},{x1,y1},{x2,y2}..]
  22. circles=[{x0,y0,10,blue,false}...]*/

上边的points和circles数组其实xy坐标是一样的,为啥创建两个呢?

如果项目小,就实现一个拖拽的图像就行了,那可以随便设置数组个数,随着标注工具增加,各种重绘,还是各干各的比较好,不要高耦合。

绘制:

  1. canvas.onmousedown=function(e){
  2. var clickX = e.pageX - canvas.offsetLeft;
  3. var clickY = e.pageY - canvas.offsetTop;
  4. //判断当前点击点是否在已经绘制的圆圈上,如果是执行相关操作,并return,不进入画线的代码
  5. for(var i=1; i<circles.length; i++) {
  6. var circle = circles[i];
  7. //使用勾股定理计算这个点与圆心之间的距离
  8. var distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2)
  9. + Math.pow(circle.y - clickY, 2));
  10.  
  11. // 如果是其他的点,则设置可以拖动
  12. if (distanceFromCenter <= circle.radius) {
  13. // 清除之前选择的圆圈
  14. index=i;
  15. isDragging=true;
  16. //停止搜索
  17. return;
  18. }
  19. }
  20. //如果点击新的位置,则进入下面的代码,绘制点
  21. context.clearRect(0,0,canvas.width,canvas.height);
  22. //遍历数组画圆
  23. var circle=new Circle(clickX,clickY);
  24. circles.push(circle);
  25. circles[0].color="green";
  26. for(var i=0; i<circles.length; i++) {
  27. var circle = circles[i];
  28. // 绘制圆圈
  29. context.globalAlpha = 0.85;
  30. context.beginPath();
  31. context.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2);
  32. context.fillStyle = circle.color;
  33. context.strokeStyle = "black";
  34. context.fill();
  35. context.stroke();
  36. }
  37. // 画线
  38. var point=new Point(clickX,clickY);
  39. points.push(point);
  40. context.beginPath();
  41. context.lineWidth = 4;
  42. //从起始点开始绘制
  43. context.moveTo(points[0].x,points[0].y);
  44. for (var i = 0; i < points.length; i++) {
  45. context.lineTo(points[i].x, points[i].y);
  46. }
  47. context.fillStyle="rgb(2,100,30)";
  48. context.fill();
  49. context.strokeStyle="#9d4dca";
  50. context.stroke();
  51. };

每一次点击都要判断一下,如果点在曾经绘制的点上,那么就设置变量isDragging=true可以拖拽,return。如果没有,说明创建的是新的点,那么开始绘制并且加入数组。(代码部分的声明就不写了,直接出关键的思路代码,具体的还要自己动手去写)

拖拽点移动:

  1. canvas.onmousemove=function(e){
  2. // 判断圆圈是否开始拖拽
  3. if (isDragging == true) {
  4. // 判断拖拽对象是否存在
  5. // 取得鼠标位置
  6. var x1 = e.pageX - canvas.offsetLeft;
  7. var y1 = e.pageY - canvas.offsetTop;
  8. context.clearRect(0,0,canvas.width,canvas.height);
  9. //根据上文得到的index设置index点位置随鼠标改变
  10. circles[index].x=x1;
  11. circles[index].y=y1;
  12. points[index].x=x1;
  13. points[index].y=y1;
  14. for(var i=0; i<circles.length; i++) {
  15. var circle = circles[i];
  16. // 绘制圆圈
  17. context.globalAlpha = 0.85;
  18. context.beginPath();
  19. context.arc(circle.x, circle.y, circle.radius, 0, Math.PI*2);
  20. context.fillStyle = circle.color;
  21. context.strokeStyle = "black";
  22. context.fill();
  23. context.stroke();
  24. }
  25. context.beginPath();
  26. context.moveTo(points[0].x,points[0].y);
  27. for (var i = 0; i < points.length; i++) {
  28. context.lineTo(points[i].x, points[i].y);
  29. }
  30. context.lineTo(points[0].x,points[0].y);
  31. // context.fillStyle="#831f68";
  32. context.fillStyle="rgb(2,100,30)";
  33. context.fill();
  34. context.strokeStyle="#9d4dca";
  35. context.stroke();
  36. }
  37. };
  38.  
  39. canvas.onmouseup=function(){
  40. isDragging=false;
  41. };
  42.  
  43. canvas.onmouseout=function(){
  44. isDragging=false;
  45. };

其实实现拖拽并不难, 有一个地方就是如何判断鼠标点在了已经绘制的点上。循环所有点,只要鼠标点到圆心的距离小于半径,那么一定点在了这个点上。

这样一个简单的拖拽就实现了,后面的文章我还会继续增加新的功能,慢慢丰富代码。欢迎关注。

更新:一个V1.0工程的视频,百度网盘:链接: https://pan.baidu.com/s/1qFF3yF4T9oE9quiUx7hfoA 密码: md6g

1.0版本,后续版本慢慢更新,包括canvas的绘制和Vue的一些东东。可绘制、拖拽、编辑、下载坐标信息,对于一些数据集的标注工作可以辅助标记。

Canvas绘制不规则图形,实现可拖动,编辑--V1.0第一篇的更多相关文章

  1. 学习笔记:HTML5 Canvas绘制简单图形

    HTML5 Canvas绘制简单图形 1.添加Canvas标签,添加id供js操作. <canvas id="mycanvas" height="700" ...

  2. Canvas学习:封装Canvas绘制基本图形API

    Canvas学习:封装Canvas绘制基本图形API Canvas Canvas学习   从前面的文章中我们了解到,通过Canvas中的CanvasRenderingContext2D对象中的属性和方 ...

  3. [html5] 学习笔记-Canvas 绘制渐变图形与绘制变形图形

    在 HTML5 中,使用 Canvas API 绘制图形的知识,可以对绘制图形进行处理,包含使用 Canvas API 绘制渐变图形,使用 Canvas API 的坐标轴变换处理功能绘制变形图形.其中 ...

  4. canvas绘制简单图形

    canvas绘图篇: canvas绘制矩形: <!DOCTYPE html> <html> <head lang="en"> <meta ...

  5. h5 的canvas绘制基本图形

    文章地址:https://www.cnblogs.com/sandraryan/ canvas是一个标签,可用于绘制复杂图形,渲染效果比普通DOM快 某些低版本浏览器不支持 canvas 使用原生几乎 ...

  6. Android采用canvas绘制各种图形

    canvas通俗的说就是一个帆布,我们可以用刷子paint,就此随机抽签显卡. 原理: 能够canvas视Surface替代或接口.图形绘制Surface向上.Canvas封装了全部的绘制调用. 通过 ...

  7. canvas绘制旋转图形

    将绘制到canvas上的要素进行旋转: 1.绘制时,通过操作画布的坐标轴状态:平移画布原点,旋转坐标轴等,达到旋转图形的目的 2.操作操作DOM元素,直接旋转canvas画布 操作画布的坐标轴状态: ...

  8. css3创建多边形clip属性,可用来绘制不规则图形了

    .path1 { clip-path: polygon(5px 10px, 16px 3px, 16px 17px); } .path2 { clip-path: polygon(3px 5px, 1 ...

  9. CSS3绘制不规则图形,代码收集

    三角形系列(三角形.倒三角.左三角.右三角.左上三角.右上三角.左下三角.右下三角) 主要用到的是:宽度高度设置为0, border的各个边的设置(各个边的透明或不透明): .triangle-up ...

随机推荐

  1. 对Numpy数组按axis运算的理解

    Python的Numpy数组运算中,有时会出现按axis进行运算的情况,如 >>> x = np.array([[1, 1], [2, 2]]) >>> x arr ...

  2. Spring-基于设置函数的依赖注入

    Spring 基于设置函数的依赖注入 当容器调用一个无参的构造函数或一个无参的静态factory方法来初始化你的bean后,通过容器在你的bean上调用设值函数,基于设值函数的DI就完成了. 下面是T ...

  3. POJO,简单的Java对象

    POJO = "Plain Ordinary Java Object",简单的Java对象,是为了避免和EJB混淆所创造的简称,是MartinFowler等发明的一个术语,用来表示 ...

  4. MySQL 参数

    I see a lot of people filtering replication with binlog-do-db, binlog-ignore-db, replicate-do-db, an ...

  5. WordPress文章自动提取tag并添加链接

    我们在编写文章时,经常需要添加一些标签关键词的链接,这样不仅可以优化我们的内链,对用户来说也可以参照相关的文章,如果对文章的关键字进行手动添加链接,那样对我们来说太麻烦了,而且在标签关键词很多的情况下 ...

  6. ElasticSearch的x-pack配置查询

    ElasticSearch在安装完x-pack后, 存在客户端通过Transport访问ES出现异常:java.lang.IllegalArgumentException: Unknown Named ...

  7. $ MySQL-python数据库模块用法

    本文主要介绍在python中如何使用MySQL数据库. 准备工作 安装mysql Linux (Ubuntu) apt-get install mysql-server 安装完成之后在命令行中输入:m ...

  8. 【Linux学习】1.Linux基础知识

    记录学习Linux 系统的相关知识点,欢迎大家拍砖交流,一起成长:QQ:2712192471 作者背景:前端开发工程师 | Python | web安全爱好者 一,Windows系统下 Linux 的 ...

  9. java 2017/6/26杂记

    mkdirs()可以建立多级文件夹, mkdir()只会建立一级的文件夹, 如下: new File("/tmp/one/two/three").mkdirs(); 执行后, 会建 ...

  10. OpenCV KNN 之 使用方法

    http://blog.csdn.net/WL2002200/article/details/43149229 OpenCV 中KNN构造函数如下. C++: CvKNearest::CvKNeare ...