先上效果图:


代码

<!DOCTYPE html>
<html>
<head><title>箭头动画</title>
</head>
<body><canvas id="myCanvas">Your browser does not support HTML5 Canvas. </canvas>
</body>
</html>
<script type="text/javascript">var myCanvas = document.getElementById("myCanvas");myCanvas.style.cssText = "position:absolute;left:0;top:0; border: 1px solid #ccc;"; // 画布样式myCanvas.width = 600;   // 画布的宽度myCanvas.height = 600;  // 画布的高度 // 画笔(绘图对象)var ctx = myCanvas.getContext('2d');var deg = 30;var hud = deg * (Math.PI / 180);var r = 100;        // 半径 (即两点距离)var p1 = {x: 300,         // X坐标y: 150          // y坐标}var p2 = {x: p1.x + Math.cos(hud) * r,   // X坐标y: p1.y - Math.sin(hud) * r    // y坐标    }// 动画效果var _index = 1;setInterval(function () {// 清空画布var BW = myCanvas.width;var BH = myCanvas.height;ctx.clearRect(0, 0, BW, BH);                // 清空画布// 用于参考倾斜度的直线ctx.strokeStyle = "red";ctx.beginPath()ctx.moveTo(p1.x, p1.y);ctx.lineTo(p2.x, p2.y);ctx.stroke();ctx.closePath();// 无效果arrowTo(ctx, p1, p2, { color: "blue" });// 高亮效果arrowTo(ctx, { x: 100, y: 150 }, { x: 250, y: 450 }, { activeIndex: _index });arrowTo(ctx, { x: 200, y: 250 }, { x: 450, y: 250 }, { activeIndex: _index });arrowTo(ctx, { x: 500, y: 50 }, { x: 450, y: 250 }, { activeIndex: _index });arrowTo(ctx, { x: 200, y: 250 }, { x: 200, y: 50 }, { activeIndex: _index });// 整体偏移效果var offset = (_index % 3) * 5;arrowTo(ctx, { x: 200, y: 400 }, { x: 500, y: 400 }, { offset: offset, color: "red", justifyAlign: false });arrowTo(ctx, { x: 500, y: 400 }, { x: 450, y: 580 }, { offset: offset, color: "red", justifyAlign: false });arrowTo(ctx, { x: 450, y: 580 }, { x: 160, y: 580 }, { offset: offset, color: "red", justifyAlign: false });arrowTo(ctx, { x: 160, y: 580 }, { x: 200, y: 400 }, { offset: offset, color: "red", justifyAlign: false });// 其他处理if (_index >= 50) {_index = 1}else {_index++;}}, 300);
</script><script type="text/javascript">// 画两点间箭头// ctx - 画布上下文(我理解成画笔)// p1 - 起点// p2 - 终点// arrowOptions -- 画箭头的选项function arrowTo(ctx, p1, p2, arrowOptions) {// 初始化参数var opts = {startOffset: 5,             // 起点的留空长度endOffset: 5,               // 终点的留空长度offset: 0,                  // 偏移位(模拟动画效果用, 使用时建议将justifyAlign设为false) color: '#E6E6FA',           // 默认颜色 activeIndex: -1,            // 高亮箭头的索引, 超出回到一圈起始位置。(默认-1,不做高亮处理) activeColor: "#00FF00",     // 高亮颜色(Highligh Color)stepLength: 10,             // 间隔(步长)justifyAlign: true,         // 两端对齐(两边撑满, 配合activeIndex > 0时使用) arrowLength: 15,            // 箭头长度(柄到顶点)            arrowTheta: 25,             // 箭头两边的夹角(度数) arrowHeadlen: 6,            // 箭头两边斜边长度 arrowLineWidth: 1,          // 画箭头的线宽度lineWidth: 1,               // 两点间的连丝宽度(>0时,有效)};if (arrowOptions !== undefined && arrowOptions !== null) {opts = Object.assign(opts, arrowOptions);}// 画连结两点的线if (opts.lineWidth > 0) {ctx.beginPath();ctx.moveTo(p1.x, p1.y);ctx.lineTo(p2.x, p2.y);//颜色,线宽ctx.strokeStyle = opts.color;ctx.lineWidth = opts.lineWidth;ctx.stroke();ctx.closePath();}// 计两点距离var len = Math.floor(Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)));// 计算画多少个箭头(注意:最后一个箭头是不需要间隔(步长),所以可用长度要加一个opts.stepLength)var loops = Math.floor((len - (opts.startOffset + opts.offset + opts.endOffset) + opts.stepLength) / (opts.arrowLength + opts.stepLength));// 两端对齐(两边撑满),重算步长 if (opts.justifyAlign === true) {opts.stepLength = (len - (opts.startOffset + opts.offset + opts.endOffset) - (opts.arrowLength * loops)) / (loops - 1);}// 高亮箭头的索引, 超出回到一圈起始位置。(用于动画效果) var highlightIndex = 0;               // 0 - 无动画效果                if (opts.activeIndex > 0) {if ((opts.activeIndex % loops) === 0) {highlightIndex = loops;}else {highlightIndex = opts.activeIndex % loops;}}var hudu = Math.atan2(p1.y - p2.y, p2.x - p1.x);    // 计算p1, p2两点的倾斜度(弧度)。(注意参数:p1.y - p2.y, p2.x - p1.x, 请勿搞错)var p0 = { x: p1.x, y: p1.y };                      // 原点坐标, 作为圆心。 (辅助计算箭头起点(柄)与顶点的坐标)var r;                                              // 半径。 (辅助计算箭头起点(柄)与顶点的坐标)var color;for (var i = 0; i < loops; i++) {// 箭头起点(柄)r = (opts.startOffset + opts.offset) + (opts.arrowLength + opts.stepLength) * i;     // 原点到箭头起点(柄)的半径p1 = {x: p0.x + Math.cos(hudu) * r,y: p0.y - Math.sin(hudu) * r};// 箭头终点(顶点)r = r + opts.arrowLength;                       // 原点到箭头顶点(柄)的半径p2 = {x: p0.x + Math.cos(hudu) * r,y: p0.y - Math.sin(hudu) * r};// 画一个箭头if (highlightIndex > 0 && i === (highlightIndex - 1)) {color = opts.activeColor;       //高亮箭头(动画效果)}else {color = opts.color;}drawArrow(ctx, p1, p2, opts.arrowTheta, opts.arrowHeadlen, opts.arrowLineWidth, color);}}// 画箭头// ctx - 画布上下文(我理解成画笔)// p1 - 起点// p2 - 终点// theta -- 夹角theta (是度数,不是弧度)// headlen -- 斜边长度// width -- 线宽// color -- 颜色function drawArrow(ctx, p1, p2, theta, headlen, width, color) {theta = (theta !== undefined && theta !== null) ? theta : 25;       //夹角(度数)headlen = (headlen !== undefined && headlen !== null) ? headlen : 6;   //斜边长度width = (width !== undefined && width !== null) ? width : 1;        //线宽color = (color !== undefined && color !== null) ? color : '#000';       //颜色var angle = Math.atan2(p1.y - p2.y, p1.x - p2.x) * 180 / Math.PI,   //倾斜度(度数)angle1 = (angle + theta) * Math.PI / 180,            //夹角1angle2 = (angle - theta) * Math.PI / 180,            //夹角2   topX = headlen * Math.cos(angle1),                   //箭头上面点, X偏移位topY = headlen * Math.sin(angle1),                   //箭头上面点, Y偏移位botX = headlen * Math.cos(angle2),                   //箭头下面点, X偏移位   botY = headlen * Math.sin(angle2);                   //箭头下面点, Y偏移位      ctx.save();ctx.beginPath();//连结两点的线ctx.moveTo(p1.x, p1.y);ctx.lineTo(p2.x, p2.y);//终点箭头的两侧var arrowX = p2.x + topX;var arrowY = p2.y + topY;ctx.moveTo(arrowX, arrowY);ctx.lineTo(p2.x, p2.y);           //终点arrowX = p2.x + botX;arrowY = p2.y + botY;ctx.lineTo(arrowX, arrowY);//颜色,线宽ctx.strokeStyle = color;ctx.lineWidth = width;ctx.stroke();ctx.restore();}// 为Object扩展assign方法(合拼多个对象的属性,返回一个新对象)if (!Object.assign) {Object.defineProperty(Object, "assign", {enumerable: false,configurable: true,writable: true,value: function (target, firstSource) {"use strict";if (target === undefined || target === null)throw new TypeError("Cannot convert first argument to object");var to = Object(target);for (var i = 1; i < arguments.length; i++) {var nextSource = arguments[i];if (nextSource === undefined || nextSource === null) continue;var keysArray = Object.keys(Object(nextSource));for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {var nextKey = keysArray[nextIndex];var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);if (desc !== undefined && desc.enumerable) to[nextKey] = nextSource[nextKey];}}return to;}});}
</script>

参考资料:
根据两点坐标,计算连线与坐标轴间的夹角(弧度、角度)(整理)

Canvas学习:绘制箭头
利用setLineDash 和 lineDashOffset 实现跑马灯(流动)效果
角度与弧度互转

角度与弧度互转

Canvas箭头动画相关推荐

  1. python制作简单动画_Python tkinter Canvas绘制动画

    其实前面程序中的高亮显示已经是动画效果了.程序会用红色.黄色交替显示几何图形的边框,这样看上去就是动画效果了.实现其他动画效果也是这个原理,程序只要增加一个定时器,周期性地改变界面上图形项的颜色.大小 ...

  2. 基于Canvas的动画基本原理与数理分析

    转载自https://www.jianshu.com/p/e70c9cfbdb38 什么是动画? 就像思考哲学问题无法回避思维和存在的关系一样,制作动画同样无法逃避的问题是动画的原理是什么?这里提一句 ...

  3. canvas粒子动画

    2019独角兽企业重金招聘Python工程师标准>>> 周末在家玩了一下canvas粒子动画,先看看效果,用的图是我们微众银行的干爹'qq',先看看效果 ##1.获取图片信息 ### ...

  4. flash动画制作成品_Flash如何制作沿曲线移动的箭头动画

    箭头动画是制作一些流程类动画经常会用到的效果,主要用到的是动作补间动画,这里就简单讲一下使用Flash软件如何制作沿着曲线移动的箭头动画效果. FLASH制作循环移动的箭头动画-百度经验​jingya ...

  5. html5在线制作教程,HTML5 Canvas 制作动画

    HTML5 Canvas 制作动画 在HTML5 canvas中绘制图像动画效果,你需要绘制出每一帧的图像,然后在一个极短的时间内从一帧过渡到下一帧,形成动画效果. 在线示例 要在HTML5画布上绘制 ...

  6. Div层悬浮实现HTML5 Canvas背景动画

    在日常的学习中我接触到一些HTML5 Canvas动画,在开发 tiomg.org 太美在线工具网站 的时候,想将这些震撼或小清新的动画融合到工具网站中,这样可以使原本单调的网页看起来丰富和更有设计感 ...

  7. html上下箭头动态效果,使用CSS和Bootstrap图标制作上下跳动的指示箭头动画效果...

    有时侯页面很长,需要指示箭头告诉用户下面还有东西.可以用纯CSS的方法实现. HTML:添加一个链接,可修改锚点点击时滑动到指定位置,这里使用了Bootstrap 3.x版本的一个向下箭头作为图标. ...

  8. css 让图标上下跳,使用CSS和Bootstrap图标制作上下跳动的指示箭头动画效果

    有时侯页面很长,需要指示箭头告诉用户下面还有东西.可以用纯CSS的方法实现. HTML:添加一个链接,可修改锚点点击时滑动到指定位置,这里使用了Bootstrap 3.x版本的一个向下箭头作为图标. ...

  9. html5字体动画效果,7款超华丽的HTML5 Canvas文字动画特效

    原标题:7款超华丽的HTML5 Canvas文字动画特效 文字是网页中最为常见的元素之一,当然我们使用最多的就是调整文字的颜色.大小等基本属性.有时候我们在一些活动页面上需要展示特别样式的文字效果,这 ...

最新文章

  1. 比亚迪秦wince玩游戏_【新闻】1.5T比亚迪秦Pro或要降价/多款亲民新车上市!
  2. Linux-grep命令
  3. docker操作语句
  4. Atcoder 084D - Small Multiple(最短路径+思维)
  5. 在WEB程序中隐藏后门
  6. LAV Filter 源代码分析 2: LAV Splitter
  7. Android 如何优化开屏广告?
  8. swfupload ajax,swfupload ajax无刷新上传图片实例代码
  9. 显示当前时间(C语言)
  10. 时空-问题集锦(转载)
  11. 网络探测工具(二)——traceroute
  12. Esky+Cx_freeze开发打包python可自动升级程序
  13. python中的self理解
  14. 雨敲窗python_标签 Python - 雨敲窗个人博客
  15. CDISC的ADaMIG (V1.2) 中英文对照【2】_第二章 ADaM标准的基础
  16. MongoDB如何开启服务
  17. 菜鸟网管的入门之路-第一章、网络及硬件篇(2安防监控)
  18. USB运动控制 (五轴雕刻机系统)全部开源
  19. 2022年(金融保险)金融行业几个比较热门的证书
  20. mysql 删除表数据_主外键关联表的数据删除策略

热门文章

  1. 语言学句法分析树形图怎么画_语言学树形图
  2. Raspberry Pi 4 树莓派4 支持操作系统
  3. 启动车子温车_车子启动后水温上的很快是什么原?
  4. Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 't.statis_date'
  5. 禅道项目管理系统安装后显示为空白
  6. 万能通用网关系统!就该这么设计,稳的一批!
  7. FreeRTOS学习,适用于FreeRTOS初学者,FreeRTOS整体知识框架
  8. 文本分类实战--从TFIDF到深度学习(附代码)
  9. 7-14 凯撒密码 (10 分)
  10. 卡片互动悬停下载动画