zoukankan      html  css  js  c++  java
  • 使用Canvas实现贝塞尔曲线显示以及控制

    贝塞尔曲线

    场景:

      创建简易的绘图工具,实现控制画布上的四个锚点的拖拽修改已经绘制的曲线图,通过注释实时显示锚点的具体实时坐标,并通过反色清楚的显示控制点的位置

    要求:
      1. 创建一个512*512的canvas画布
      2. 在该画布上任意创建四个锚点,使用贝塞尔曲线进行连接
      3. 可在画布上自由拖拽上面的锚点,从而实现贝塞尔曲线的联动,每个点都有一个跟随点移动的注释(文字+箭头),说明该点的坐标
      4.在此基础上,实现一个黑白渐变色的背景,然后在锚点周围20个像素内,将锚点所处的背景作反色,突出锚点的显示

    思路整理: 

      明确:

        贝塞尔曲线通过canvas绘制,canvas自带贝塞尔曲线绘制方法 bezierCurveTo()

         显示锚点可以在canvas上覆盖div 将锚点放在div中

        锚点拖动,添加事件监听, 鼠标按下  为被点击的锚点 添加鼠标移动事件,松开 注销鼠标移动事件

       拖动锚点时要做什么?

        修改注释内的坐标

        canvas根据锚点坐标重绘贝塞尔曲线

        锚点周围20像素背景色取反

     效果展示

    代码(随手写 可自行优化完善)

      1 <style>
      2     * {
      3         margin: 0;
      4         padding: 0;
      5     }
      6 
      7     #myCanvas {
      8         position: absolute;
      9     }
     10 
     11     span {
     12         position: absolute;
     13          20px;
     14         height: 20px;
     15         background: #21e40f;
     16         border: 20px solid #fff;
     17         border-radius: 50%;
     18         color: rgb(25, 6, 204);
     19         text-align: center;
     20         font-size: 14px;
     21         top: 50px;
     22         left: 50px;
     23     }
     24 
     25     #end {
     26         top: 50px;
     27         left: 350px;
     28     }
     29 
     30     #dot1 {
     31         top: 350px;
     32         left: 50px;
     33     }
     34 
     35     #dot2 {
     36         top: 350px;
     37         left: 350px;
     38     }
     39 
     40     i {
     41         position: absolute;
     42         display: block;
     43          60px;
     44         height: 40px;
     45         background: rgba(121, 212, 170, 0.3);
     46         left: 30px;
     47         top: 30px;
     48     }
     49 </style>
     50 
     51 <body>
     52     <!-- 要求:
     53     1. 创建一个512*512的canvas画布
     54     2. 在该画布上任意创建四个锚点,使用贝塞尔曲线进行连接
     55     3. 可在画布上自由拖拽上面的锚点,从而实现贝塞尔曲线的联动,每个点都有一个跟随点移动的注释(文字+箭头),说明该点的坐标
     56     4. 在此基础上,实现一个黑白渐变色的背景,然后在锚点周围20个像素内,将锚点所处的背景作反色,突出锚点的显示 -->
     57 
     58     <!-- 画布 -->
     59     <canvas id="myCanvas" width="512" height="512" style="border:1px solid #000000;">
     60     </canvas>
     61     <!-- 画布遮罩层  用于锚点显示控制 -->
     62     <div id="box">
     63         <!-- 四个锚点 开始  结束  锚点1  锚点2-->
     64         <span id="start">1 <i>1</i></span>
     65         <span id="dot1">2 <i>2</i></span>
     66         <span id="dot2">3 <i>3</i></span>
     67         <span id="end">4 <i>4</i></span>
     68     </div>
     69 
     70     <script>
     71         //画布渐变等
     72         var c, ctx, grd;
     73         //四个锚点
     74         var start, end, dot1, dot2, liArr;
     75 
     76         //坐标等
     77         var x = 0;
     78         var y = 0;
     79         var l = 0;
     80         var t = 0;
     81         var isDown = false;
     82 
     83         init();
     84         function init() {
     85             // 获取锚点
     86             start = document.querySelector('#start')
     87             end = document.querySelector('#end')
     88             dot1 = document.querySelector('#dot1')
     89             dot2 = document.querySelector('#dot2')
     90             //锚点文字说明以及跟随样式
     91             liArr = document.querySelectorAll('i');
     92             //获取画布
     93             c = document.getElementById("myCanvas");
     94             ctx = c.getContext("2d");
     95             // 创建渐变
     96             grd = ctx.createLinearGradient(0, 0, 512, 0);
     97             grd.addColorStop(0, "black");
     98             grd.addColorStop(1, "white");
     99             // 填充渐变
    100             ctx.fillStyle = grd;
    101             ctx.fillRect(0, 0, 512, 512);
    102         
    103             start.addEventListener('mousedown', downHandler)
    104             end.addEventListener('mousedown', downHandler)
    105             dot1.addEventListener('mousedown', downHandler)
    106             dot2.addEventListener('mousedown', downHandler)
    107 
    108             start.addEventListener('mouseup', upHandler)
    109             end.addEventListener('mouseup', upHandler)
    110             dot1.addEventListener('mouseup', upHandler)
    111             dot2.addEventListener('mouseup', upHandler)
    112 
    113             ctx.beginPath();
    114             drawLine()
    115             ctx.stroke();
    116         }
    117         //鼠标按下回调
    118         function downHandler(e) {
    119             e.stopPropagation();
    120             // 获取x坐标和y坐标
    121             x = e.clientX;
    122             y = e.clientY;
    123             //获取左部和顶部的偏移量
    124             l = e.target.offsetLeft;
    125             t = e.target.offsetTop;
    126             //开关打开
    127             isDown = true;
    128             //设置样式  
    129             e.target.style.cursor = 'move';
    130             //添加移动侦听
    131             e.target.addEventListener('mousemove', moveHandler)
    132             e.target.addEventListener('mouseup', moveHandler)
    133         }
    134         //拖拽回调
    135         function moveHandler(e) {
    136             if (isDown == false) {
    137                 return;
    138             }
    139             //获取x和y
    140             var nx = e.clientX;
    141             var ny = e.clientY;
    142             //计算移动后的左偏移量和顶部的偏移量
    143             var nl = nx - (x - l);
    144             var nt = ny - (y - t);
    145 
    146             e.target.style.left = nl + 'px';
    147             e.target.style.top = nt + 'px';
    148 
    149             ctx.beginPath();
    150             drawLine();
    151             ctx.stroke();
    152         }
    153 
    154         function upHandler(e) {
    155             //注销移动侦听事件
    156             e.target.removeEventListener('mousemove', moveHandler)
    157         }
    158         //绘制贝塞尔曲线 /  设置 文字  /  背景反色
    159         function drawLine() {
    160             //获取锚点坐标
    161             let s1 = setNum(start.offsetLeft);
    162             let s2 = setNum(start.offsetTop);
    163             let e1 = setNum(end.offsetLeft);
    164             let e2 = setNum(end.offsetTop);
    165             let dd1 = setNum(dot1.offsetLeft);
    166             let dd2 = setNum(dot1.offsetTop);
    167             let dd3 = setNum(dot2.offsetLeft);
    168             let dd4 = setNum(dot2.offsetTop);
    169 
    170             ctx.clearRect(20, 20, 100, 50);
    171             ctx.fillStyle = grd;
    172             ctx.fillRect(0, 0, 512, 512);
    173 
    174             ctx.moveTo(s1, s2)
    175             ctx.bezierCurveTo(dd1, dd2, dd3, dd4, e1, e2);
    176             //显示更新锚点坐标
    177             liArr[0].innerText = `x=> ${s1} x=> ${s2}`;
    178             liArr[1].innerText = `x=> ${dd1} x=> ${dd2}`;
    179             liArr[2].innerText = `x=> ${dd3} x=> ${dd4}`
    180             liArr[3].innerText = `x=> ${e1} x=> ${e2}`
    181 
    182             //设置边框颜色
    183             setColor(start, s1, s2);
    184             setColor(end, e1, e2);
    185             setColor(dot1, dd1, dd2);
    186             setColor(dot2, dd3, dd4);
    187         }
    188         //处理贝塞尔曲线坐标点, 与div 中心重合
    189         function setNum(str) {
    190             return parseInt(str) + 30
    191         }
    192         //设置背景色反色
    193         function setColor(target, x, y) {
    194             let col = ctx.getImageData(x, y, 1, 1).data;
    195             for (let i = 0; i < col.length; i++) {
    196                 col[i] = 255 - col[i]
    197             }
    198             console.log(target, col);
    199             target.style.border = `20px solid rgb(${col[0]},${col[1]},${col[2]})`
    200         }
    201     </script>
    202 </body>

    --

  • 相关阅读:
    艰苦创业,无怨无悔,他靠养蜂开拓创业路!
    农民工如何拥有500多家加盟连锁店,看他是怎样做到的?
    从小面馆到餐饮王国,他的成功靠的是什么?
    夫妻合体创业,两月收入15万,他们是怎样做到的?
    农民王永宝,打造了一片乡村旅游乐土
    10年时间,从摆地摊到开连锁店,他们夫妻二人如何度过?
    F5 服务说明
    python 获取pool 成员状态
    CloudCC CRM探讨:精细流程管理与员工悟性培养
    CloudCC CRM探讨:精细流程管理与员工悟性培养
  • 原文地址:https://www.cnblogs.com/rookieKong/p/13757572.html
Copyright © 2011-2022 走看看