热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用Raphael绘制流程图,自绘动态箭头,可拖动,有双击事件,纯前端,兼容各种浏览器...

关于RaphalRaphal是一个在网页上绘图的js类库,非常小压缩版只有89k左右官方宣称兼容各种主流浏览器,据笔者测试在IE6下尚有一些问题

关于Raphaël

Raphaël是一个在网页上绘图的js类库,非常小压缩版只有89k左右

官方宣称兼容各种主流浏览器,据笔者测试在IE6下尚有一些问题(不过这些与本文无关)

他是使用js来创建vml或svg来绘图的

缘起

项目中不能使用Silverlight或者flash来解决绘图和拖动的问题

而且为了项目效果较好,要求拖动的时候箭头能动态改变起点和重点,别且箭头要改变方向

所以只能考虑JS了

效果

image

演示

http://www.mrlh.net/flowchart/demo.htm[已经不能访问了]

源码

引用

这两个东西是不相干的,引用先后顺序也无所谓

页面加载完成后的代码

$(function () {//用来存储节点的顺序var connections = [];//拖动节点开始时的事件var dragger = function () {this.ox = this.attr("x");this.oy = this.attr("y");this.animate({ "fill-opacity": .2 }, 500);};//拖动事件var move = function (dx, dy) {var att = { x: this.ox + dx, y: this.oy + dy };this.attr(att);$("#test" + this.id).offset({ top: this.oy + dy + 10, left: this.ox + dx + 10 });for (var i = connections.length; i--; ) {r.drawArr(connections[i]);}};//拖动结束后的事件var up = function () {this.animate({ "fill-opacity": 0 }, 500);};//创建绘图对象var r = Raphael("holder", $(window).width(), $(window).height());//绘制节点var shapes = [r.rect(190, 100, 60, 40, 4),r.rect(290, 80, 60, 40, 4),r.rect(290, 180, 60, 40, 4),r.rect(450, 100, 60, 40, 4)];//定位节点上的文字$("#test1").offset({ top: 100 + 10, left: 190 + 10 });$("#test2").offset({ top: 80 + 10, left: 290 + 10 });$("#test3").offset({ top: 180 + 10, left: 290 + 10 });$("#test4").offset({ top: 100 + 10, left: 450 + 10 });//为节点添加样式和事件,并且绘制节点之间的箭头for (var i = 0, ii = shapes.length; i

这些代码注释比较详细,就不多说了

在这些代码中涉及到操作的界面元素HTML代码如下

测试1
测试2
测试3
测试4

其中关键元素的样式如下

#holder{top: 0px;left: 0px;right: 0px;bottom: 0px;position: absolute;z-index: 999;}test{position: absolute;width: 80px;height: 30px;top: 0px;z-index: 0;}

在拖动事件中,动态改变了节点文本元素的位置

并且重绘了节点和箭头

drawArr是一个自定义方法,负责修改箭头的方向,代码如下

//随着节点位置的改变动态改变箭头Raphael.fn.drawArr = function (obj) {var point = getStartEnd(obj.obj1, obj.obj2);var path1 = getArr(point.start.x, point.start.y, point.end.x, point.end.y, 8);if (obj.arrPath) {obj.arrPath.attr({ path: path1 });} else {obj.arrPath = this.path(path1);}return obj;};

首先需要确定箭头的起始位置,

point包含两个点,

point.start为起点,

point.end为终点,

然后需要确定箭头的绘图路径

一个箭头包含三个线段,四个点

1:起点,2:终点,3:箭头终点1,4:箭头终点2

image

在此函数中,判断如果箭头已经被绘制过,

只要修改属性即可

如果没有被绘制过,则需要重新绘制

 

下面来看一下动态确定起点和终点的代码

function getStartEnd(obj1, obj2) {var bb1 &#61; obj1.getBBox(),bb2 &#61; obj2.getBBox();var p &#61; [{ x: bb1.x &#43; bb1.width / 2, y: bb1.y - 1 },{ x: bb1.x &#43; bb1.width / 2, y: bb1.y &#43; bb1.height &#43; 1 },{ x: bb1.x - 1, y: bb1.y &#43; bb1.height / 2 },{ x: bb1.x &#43; bb1.width &#43; 1, y: bb1.y &#43; bb1.height / 2 },{ x: bb2.x &#43; bb2.width / 2, y: bb2.y - 1 },{ x: bb2.x &#43; bb2.width / 2, y: bb2.y &#43; bb2.height &#43; 1 },{ x: bb2.x - 1, y: bb2.y &#43; bb2.height / 2 },{ x: bb2.x &#43; bb2.width &#43; 1, y: bb2.y &#43; bb2.height / 2 }];var d &#61; {}, dis &#61; [];for (var i &#61; 0; i <4; i&#43;&#43;) {for (var j &#61; 4; j <8; j&#43;&#43;) {var dx &#61; Math.abs(p[i].x - p[j].x),dy &#61; Math.abs(p[i].y - p[j].y);if ((i &#61;&#61; j - 4) ||(((i !&#61; 3 && j !&#61; 6) || p[i].x p[j].x) &&((i !&#61; 0 && j !&#61; 5) || p[i].y > p[j].y) &&((i !&#61; 1 && j !&#61; 4) || p[i].y

这段代码来自Raphael官方demo

不是我写的

也一时半会说不清楚&#xff0c;

大家还是自己去研究吧

 

确定箭头路径的代码如下

//获取组成箭头的三条线段的路径function getArr(x1, y1, x2, y2, size) {var angle &#61; Raphael.angle(x1, y1, x2, y2);//得到两点之间的角度var a45 &#61; Raphael.rad(angle - 45);//角度转换成弧度var a45m &#61; Raphael.rad(angle &#43; 45);var x2a &#61; x2 &#43; Math.cos(a45) * size;var y2a &#61; y2 &#43; Math.sin(a45) * size;var x2b &#61; x2 &#43; Math.cos(a45m) * size;var y2b &#61; y2 &#43; Math.sin(a45m) * size;var result &#61; ["M", x1, y1, "L", x2, y2, "L", x2a, y2a, "M", x2, y2, "L", x2b, y2b];return result;}

此函数把箭头路径作为数组反馈给调用函数

数组中

M表示画笔起点移动到此点

L表示从某点绘制到某点&#xff0c;绘制直线

以上函数反馈结果的意思是&#xff1a;

画笔从&#xff08;x1,y1&#xff09;开始绘制直线到(x2,y2),然后从(x2,y2)绘制直线到(x2a,y2a)然后画笔移动到(x2,y2)然后从(x2,y2)绘制直线到(x2b,y2b)

在确定这几个点的过程中

用到了一些数学知识&#xff0c;具体原理也不多说了

 

 

喜欢的朋友请点支持&#xff01;谢谢大家&#xff01;

转:https://www.cnblogs.com/liulun/archive/2012/05/18/2507472.html



推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了绕过WAF的XSS检测机制的方法,包括确定payload结构、测试和混淆。同时提出了一种构建XSS payload的方法,该payload与安全机制使用的正则表达式不匹配。通过清理用户输入、转义输出、使用文档对象模型(DOM)接收器和源、实施适当的跨域资源共享(CORS)策略和其他安全策略,可以有效阻止XSS漏洞。但是,WAF或自定义过滤器仍然被广泛使用来增加安全性。本文的方法可以绕过这种安全机制,构建与正则表达式不匹配的XSS payload。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 通过Anaconda安装tensorflow,并安装运行spyder编译器的完整教程
    本文提供了一个完整的教程,介绍了如何通过Anaconda安装tensorflow,并安装运行spyder编译器。文章详细介绍了安装Anaconda、创建tensorflow环境、安装GPU版本tensorflow、安装和运行Spyder编译器以及安装OpenCV等步骤。该教程适用于Windows 8操作系统,并提供了相关的网址供参考。通过本教程,读者可以轻松地安装和配置tensorflow环境,以及运行spyder编译器进行开发。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
  • 本文详细介绍了在Linux虚拟化部署中进行VLAN配置的方法。首先要确认Linux系统内核是否已经支持VLAN功能,然后配置物理网卡、子网卡和虚拟VLAN网卡的关系。接着介绍了在Linux配置VLAN Trunk的步骤,包括将物理网卡添加到VLAN、检查添加的VLAN虚拟网卡信息以及重启网络服务等。最后,通过验证连通性来确认配置是否成功。 ... [详细]
author-avatar
mobiledu2502878383
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有