jsplumb怎么设置鼠标悬浮事件在线上的央视

jsPlumb插件做一個模仿viso的可拖拉流程圖
这是我第一次写博客,心情还是有点小小的激动!这次主要分享的是用jsPlumb,做一个可以给用户自定义拖拉的流程图,并且可以序列化保存在服务器端。
我在这次的实现上面做得比较粗糙,还有分享我在做jsPlumb流程图遇到的一些问题。
制作流程图用到的相关的脚本:
1 &script src="&%= ResolveUrl("~/resources/jquery/jquery-1.11.1.min.js")%&" type="text/javascript"&&/script&
&script src="&%= ResolveUrl("~/resources/jquery-ui-1.10.4/js/jquery-ui-1.10.4.min.js") %&" type="text/javascript"&&/script&
&script src="&%= ResolveUrl("~/resources/jquery-plugins/jquery.jsPlumb-1.6.2-min.js") %&" type="text/javascript"&&/script&
jsPlumb-1.6.2-min.js在官网上下载,这里用得是最新版本。jquery-1.11.1.min.js等脚本百度上都能找到,这里就不多说了。
css样式在官网里也可以搜到,这里我就贴出来。
box-shadow: 2px 2px 19px #aaa;
-o-box-shadow: 2px 2px 19px #aaa;
-webkit-box-shadow: 2px 2px 19px #aaa;
-moz-box-shadow: 2px 2px 19px #aaa;
-moz-border-radius: 0.5em;
border-radius: 0.5em;
opacity: 0.8;
filter: alpha(opacity=80);
border: 1px solid #346789;
width: 150px;
/*line-height: 40*/
text-align: center;
z-index: 20;
position: absolute;
background-color: #eeeeef;
color: black;
padding: 10px;
font-size: 9pt;
cursor: pointer;
height: 50px;
line-height: 50px;
border-radius: 25em;
.node:hover {
box-shadow: 2px 2px 19px #;
-o-box-shadow: 2px 2px 19px #;
-webkit-box-shadow: 2px 2px 19px #;
-moz-box-shadow: 2px 2px 19px #;
opacity: 0.8;
filter: alpha(opacity=80);
&这里还有提到一点,jsPlumb官网上的api全是英文的,博主我从小英文就不好,所以看里面的doc非常费劲,一般都是一边开着金山翻译,
一边看着文档,英语好的略过这段。
言归正传,现在开始我们的jsPlumb流程图制作,下面先附上流程图。
根据客户的要求,我们要完成的功能点有以下几点:
1.支持将左边的div层拖拉到右边中间的层,并且左边同一个div拖拉没有次数限制,如果只能拖拉一次,做这个东西就没有什么意义了。
2.拖拉到中间的div层可以拖动,拖动不能超过中间div的边框。
3.拖动到中间的层,四周能有4个endpoint点,可供客户连线。
4.能支持删除多余的div的功能。
5.支持删除连接线。
6.能双击修改流程图的文字。
7.能序列化保存流程图。
下面我们根据功能开始制作:
1.拖拉jsPlumb其实是提供draggable方法,和droppable方法官网里有介绍, 但是我这里用得是jquery里的draggable()和droppable()。
1 &div id="left"&
&div class="node radius" id="node1"&开始&/div&
&div class="node" id="node2"&流程&/div&
&div class="node" id="node3"&判断&/div&
&div class="node radius" id="node4"&结束&/div&
&div id="right"&
&p&拖拉到此区域&/p&
&div id="save"&
&input type="button" value="保存" onclick="save()" /&
$("#left").children().draggable({
helper: "clone",
scope: "ss",
helper:"clone"表示,scope:"ss"是一个标识为了判断是否可以放置,主要用于droppable方法里面也设置这个标识来判断拖放到的地方,
除非两个都不写scope,可以随便拖放,但是会有一个问题,每次我从左边拖东西到右边,我再拖到的时候就会有div拖到不了,所以最好设置
scope:"//里面的值随便,只是一个标识"。
下面是完整的拖放:
1 $("#left").children().draggable({
helper: "clone",
scope: "ss",
$("#right").droppable({
scope: "ss",
drop: function (event, ui) {
var left = parseInt(ui.offset.left - $(this).offset().left);
var top = parseInt(ui.offset.top - $(this).offset().top);
var name = ui.draggable[0].
switch (name) {
case "node1":
var id = "state_start" +
$(this).append('&div class="node" style="border-radius: 25em"
id="' + id + '" &' + $(ui.helper).html() + '&/div&');
$("#" + id).css("left", left).css("top", top);
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
jsPlumb.draggable(id);
$("#" + id).draggable({ containment: "parent" });
doubleclick("#" + id);
case "node2":
id = "state_flow" +
$(this).append("&div class='node' id='" + id + "'&" + $(ui.helper).html() + "&/div&");
$("#" + id).css("left", left).css("top", top);
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, hollowCircle);
jsPlumb.draggable(id);
$("#" + id).draggable({ containment: "parent" });
doubleclick("#" + id);
case "node3":
id = "state_decide" +
$(this).append("&div class='node' id='" + id + "'&" + $(ui.helper).html() + "&/div&");
$("#" + id).css("left", left).css("top", top);
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, hollowCircle);
jsPlumb.draggable(id);
$("#" + id).draggable({ containment: "parent" });
doubleclick("#" + id);
case "node4":
id = "state_end" +
$(this).append('&div class="node" style="border-radius: 25em"
id="' + id + '" &' + $(ui.helper).html() + '&/div&');
$("#" + id).css("left", left).css("top", top);
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
jsPlumb.draggable(id);
$("#" + id).draggable({ containment: "parent" });
doubleclick("#" + id);
怎么样把左边的层到右边的层,我的做法是这样的:
1 $(this).append('&div class="node" style="border-radius: 25em"
id="' + id + '" &' + $(ui.helper).html() + '&/div&');
做到这里会有人奇怪,怎么做到左边能拉无数次append到右边,id这样不会冲突吗?我就在外面var i=0; 当有元素拖放到右边的div时,i++;
然后var id="state_start"+i;拼接起来,这样你的id就不会一样了。
然后再设置div的left和top:
drop: function (event, ui) {
var left = parseInt(ui.offset.left - $(this).offset().left);
var top = parseInt(ui.offset.top - $(this).offset().top);
$("#" + id).css("left", left).css("top", top);
2.拖拉到中间的div层可以拖动,拖动不能超过中间div的边框:
jsPlumb.draggable(id);$("#" + id).draggable({ containment: "parent" });
3.拖动到中间的层,四周能有4个endpoint点,可供客户连线:
这个功能是本文的重点,如何通过jsPlumb初始化端点和构造端点(endpoint)。
3.1 初始化端点样式设置:主要设置一些基本的端点,连接线的样式,里面的属性不设置,默认使用默认值
//基本连接线样式
var connectorPaintStyle = {
lineWidth: 4,
strokeStyle: "#61B7CF",
joinstyle: "round",
outlineColor: "white",
outlineWidth: 2
// 鼠标悬浮在连接线上的样式
var connectorHoverStyle = {
lineWidth: 4,
strokeStyle: "#216477",
outlineWidth: 2,
outlineColor: "white"
16 var hollowCircle = {
endpoint: ["Dot", { radius: 8 }],
//端点的形状
connectorStyle: connectorPaintStyle,//连接线的颜色,大小样式
connectorHoverStyle: connectorHoverStyle,
paintStyle: {
strokeStyle: "#1e8151",
fillStyle: "transparent",
radius: 2,
lineWidth: 2
//端点的颜色样式
//anchor: "AutoDefault",
isSource: true,
//是否可以拖动(作为连线起点)
connector: ["Flowchart", { stub: [40, 60], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }],
//连接线的样式种类有[Bezier],[Flowchart],[StateMachine ],[Straight ]
isTarget: true,
//是否可以放置(连线终点)
maxConnections: -1,
// 设置连接点最多可以连接几条线
connectorOverlays: [["Arrow", { width: 10, length: 10, location: 1 }]]
3.2 构造端点(endpoint):怎样将端点添加到div的四周?
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
通过jsPlumb.addEndpoint(a,b,c)里面有三个参数,a:要添加端点的div的b:设置端点放置的位置("TopCenter","RightMiddle","BottomCenter","LeftMiddle")
四个初始位置;c:端点和连接线的样式。b,c(可选).
添加多个端点:jsPlumb.addEndpoints(a,b,c)三个参数 c(可选),a:要添加端点的div的b:含端点的构造函数参数的对象列表;
举个例子:
4.支持删除多余的div的功能:
有时候拖拉div经常会发生拖多了等问题,所有需要删除功能。我要做的删除效果是:鼠标放到div上面,div的会出现一个红色的删除图标,鼠标移走就消失。如下图:
我是通过以下代码实现的:
$("#right").on("mouseenter", ".node", function () {
$(this).append('&img src="../../resources/images/close2.png"
style="position:" /&');
if ($(this).text() == "开始"
$(this).text() == "结束") {
$("img").css("left", 158).css("top", 0);
$("img").css("left", 158).css("top", -10);
$("#right").on("mouseleave", ".node", function () {
$("img").remove();
我想在这里大家都有疑问吧,为什么用on()事件委托。因为&img /&是后添加进来的元素,前面页面已经完成了初始化,所以你用$("img")根本找不到这个元素,
因为img是在页面初始化后,才添加的元素。这里就提到了live()为什么不用这个,jquery1.7.2才有这个方法,这里用的是jquery1.11.1 已经没有live()方法了,
取而代之的是on()方法。(live()有许多缺点,所以在新的版本被摒弃了)
后面删除比较简单:
$("#right").on("click", "img",function () {
if (confirm("确定要删除吗?")) {
jsPlumb.removeAllEndpoints($(this).parent().attr("id"));
$(this).parent().remove();
注明:这里我遇到一个问题,你删除了那个div,你还得把它周围的4个端点(endpoint)删除,这个问题刚开始我想了很多,一直没做出来,后来去jsPlumb官网查看相关的资料,
发现jsPlumb提供一个方法能删除div四周的端点。方法如下:
jsPlumb.removeAllEndpoints($(this).parent().attr("id"));//删除指定id的所有端点
5.支持删除连接线:
jsPlumb.bind("click", function (conn, originalEvent) {
if (confirm("确定删除吗?
jsPlumb.detach(conn);
6.&能双击修改流程图的文字:
function doubleclick(id) {
$(id).dblclick(function () {
var text = $(this).text();
$(this).html("");
$(this).append("&input type='text' value='" + text + "' /&");
$(this).mouseleave(function () {
$(this).html($("input[type='text']").val());
7.能序列化保存流程图:
我的思路是这样的,将中间div里所有的"流程图div信息和连接线两端的信息"保存到数组里,然后序列化成json数据,通过ajax传到asp.net 后台,将json写入到txt文档里保存到服务器端。
(其实保存到数据库里是最好的,后面会考虑保存到数据库),下次展示页面的时候,只要读取txt文档里的json,然后再转成泛型集合。
将页面上的div信息,和连线信息转成json跳转到ajax.aspx页面:
function save() {
var connects = [];
$.each(jsPlumb.getAllConnections(), function (idx, connection) {
connects.push({
ConnectionId: connection.id,
PageSourceId: connection.sourceId,
PageTargetId: connection.targetId,
SourceText: connection.source.innerText,
TargetText: connection.target.innerText,
var blocks = [];
$("#right .node").each(function (idx, elem) {
var $elem = $(elem);
blocks.push({
BlockId: $elem.attr('id'),
BlockContent: $elem.html(),
BlockX: parseInt($elem.css("left"), 10),
BlockY: parseInt($elem.css("top"), 10)
var serliza = JSON.stringify(connects) + "&" + JSON.stringify(blocks);
type: "post",
url: "ajax.aspx",
data: { id: serliza },
success: function (filePath) {
window.open("show-flowChart.aspx?path=" + filePath);
ajax.aspx页面将前台传过来的json保存到服务器端,并跳转至 show-flowChart.aspx:
protected void Page_Load(object sender, EventArgs e)
if (!IsPostBack)
string str = Request["id"];
string filePath = Server.MapPath("~/prototype/project-reply")+"\\json"+DateTime.Now.ToString("yyyyMMddhhmmss")+".txt";
WriteToFile(filePath,str,false);
//Response.Redirect("show-flowChart.aspx?path="+filePath);
Response.Write(filePath);
public static void WriteToFile(string name, string content, bool isCover)
FileStream fs = null;
if (!isCover && File.Exists(name))
fs = new FileStream(name, FileMode.Append, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
sw.WriteLine(content);
sw.Flush();
sw.Close();
File.WriteAllText(name, content, Encoding.UTF8);
if (fs != null)
fs.Close();
&show-flowChart.aspx页面:
1 protected void Page_Load(object sender, EventArgs e)
if (!IsPostBack)
string str = Request["path"];
StreamReader sr = new StreamReader(str);
string jsonText = sr.ReadToEnd();
List&JsPlumbConnect& list = new JavaScriptSerializer().Deserialize&List&JsPlumbConnect&&(jsonText.Split('&')[0]);
List&JsPlumbBlock& blocks = new JavaScriptSerializer().Deserialize&List&JsPlumbBlock&&(jsonText.Split('&')[1]);
string htmlText = "";
string conn = "";
if (blocks.Count & 0)
foreach (JsPlumbBlock block in blocks)
if(block.BlockContent=="开始"block.BlockContent=="结束")
htmlText += "&div class='node radius' id='" + block.BlockId + "'style='left:"+block.BlockX+"top:"+block.BlockY+"' &" + block.BlockContent + "&/div&";
htmlText += "&div class='node' id='" + block.BlockId + "'style='left:" + block.BlockX + "top:" + block.BlockY + "' &" + block.BlockContent + "&/div&";
foreach (JsPlumbConnect jsplum in list)
conn += "jsPlumb.connect({ source: \"" + jsplum.PageSourceId + "\", target: \"" + jsplum.PageTargetId + "\" }, flowConnector);";
Literal1.Text = htmlT
string script = "jsPlumb.ready(function () {" + conn + "});";
ClientScript.RegisterStartupScript(this.GetType(), "myscript", script, true);
以及两个用到的类JsPlumbConnect类和JsPlumbBlock类:
1 /// &summary&
/// 连接线信息
/// &/summary&
public class JsPlumbConnect
public string ConnectionId { get; set; }
public string PageSourceId { get; set; }
public string PageTargetId { get; set; }
public string SourceText { get; set; }
public string TargetText { get; set; }
/// &summary&
/// 流程图的所有div
/// &/summary&
public class JsPlumbBlock
/// &summary&
/// div Id
/// &/summary&
public string BlockId { get; set; }
/// &summary&
/// div里面的内容
/// &/summary&
public string BlockContent { get; set; }
public int BlockX { get; set; }
public int BlockY { get; set; }
转载请注明出处,谢谢!
附件下载地址:/s/1jGC8XM2
Database error: [Table 'ac_search_cache' is marked as crashed and should be repaired]SELECT * FROM ac_search_cache WHERE hash = '22e18a85eb92ed2d054dd9e8be02fae' LIMIT 1;jsplumb介绍-博泰典藏网
典藏文档 篇篇精品
jsplumb介绍
导读:jsPlumb介绍,以下jsPlumb介绍基于jsPlubm1.3.3版本,本文档不做介绍,官方示例:/jsPlumb/htm,jsPlumb介绍ShenBY沈本义(qq:)以下jsPlumb介绍基于jsPlubm1.3.3版本,并且基础库是用jQuery1.3.x或以上,与其他版本基础库或jsPlumb的比jsPlumb介绍 ShenBY 沈本义(qq:)
以下jsPlumb介绍基于jsPlubm1.3.3版本,并且基础库是用jQuery1.3.x或以上,与其他版本基础库或jsPlumb的比较或后期版本升级,本文档不做介绍。 本人英文水平有限,有疑惑请自行到官网对照翻译。 摘要 Jsplumb是Jquery的一个插件,它能够让你用动态的或静态的链接来连接html界面上行的元素,并且从1.1.0版本开始,提供用鼠标拖动来链接。目前该插件支持三个javascript库,有Jquery、MooToos、Yui3,jsplumb代码是开源的,并且是麻省理工学院许可,由google进行代码托管。 官方示例:/jsPlumb/html/demo.html 代码地址:/p/jsplumb/ Jsplumb介绍地址:/ JsPlumb允许您使用SVG、Canvas 或者 VML链接屏幕上的元素,这些取决于您使用的浏览器的能力。
浏览器的兼容性 jsPlumb 1.3.3 已经在以下浏览器测试: IE 6 on Windows XP IE 7 on Windows XP IE 8 on Windows XP Firefox 3.5.8 on Windows XP IE 9 on Windows 7 Chrome 12 on Windows 7 Firefox 3.5.8 on Windows 7 Firefox 3.6.3 on Ubuntu 10.04 Chrome on Ubuntu 10.04 Safari 4 on Mac Tiger Safari 4 on Windows Vista Safari 5.0.5 on Windows 7 Opera 10.54 on Windows XP 一. 安装 1. 需要导入 使用jsPlumb需要到如的类库文件,是根据您使用的javascript类库的不同而定,目前提供以下版本。 jQuery
jquery的1.3.x或更高版本 jquery ui的1.7.x或1.8.x(如果您需要支持拖放)
MooTools核心库版本1.2.4或更高版本(jsPlumb已在1.2.4和1.3.3版本上测试) MooTools的Drag.Move的1.2.4.4或更高版本
YUI3.3.X ,目前jsPlumb只在YUI3.3.0上测试,YUI3其他版本可能也可以正常工作
jsPlumb可以使用SVG,HTML5的画布元素或VML去呈现需要显示的对象,现代大部分浏览器都支持Canvas 和 SVG,但是IE9以下都不支持这些,默认情况下,jsPlumb都使用canvas去渲染,但如果在使用IE9以下的情况下,jsPlumb将使用vml去渲染,您可以通过下列方式调整渲染模式:
二.简介 1. 基本概念 jsPlumb是将所有链接的东西放在一起,所以在jsPlumb中,核心是链接对象,jsPlumb本身可以分成四个组成部分
锚(Anchor):一个位置,放置端点的地方,相对于一个元素的来源,您不需要自己硬编码来创建它,jsPlumb提供给您各种功能,您只需要按照您的需要创建它就可以了。它没有可视化的显示,只是一个逻辑位置,可以使用锚的id来引用它,jsPlumb支持这样做,并且您可以使用坐标来表示[x,y,x方向,y方向]
端点(Endpoint ):链接的一端的可视化表示,您可以创建并可以链接他们;您可以连接器(Connector):链接两个元素的线,页面的可视化表示,jsPlumb有三种默认让他们支持拖拽,或者您可以直接使用jsPlumb.connect()在创建链接时直接创建它们。
类型:Bezier曲线,直线,和流程图链接器,您不用去处理连接器,当您需要使用它们时,您只需要定义它们即可。
覆盖物(Overlay):一个UI组件,是用来是用来装饰连接器,例如标签、箭头等。 2. 锚(Anchors) 锚的概念是指:定义一个链接线能够链接的点,jsPlumb有9个默认的锚点位置,您可以使用它们去链接元素,具体有:
这些位置在jsplumb底层代码中都是以阵列语法表示的,[X,Y,DX,DY],其中X,Y是在区间[0,1]指定锚的位置,DX和DY是在区间[-1,1]指定曲线的事件锚的方向坐标,例如[0,0.5,-1,0]定义了一个“LeftCenter”连接器的曲线,从锚点单向向左的曲线.同样,[0.5,0,0,-1],定义一个“CenterTop”锚连接器所产生的向上的曲线。 3. 动态锚(Dynamic Anchors) 这些都是可以在若干地点之一定位的锚点,当你每次移动一个元素时,会自动选择一个最合适的位置,没有特殊的语法来创建一个DynamicAnchor,你只需要提供一个独立的锚位置,例如数组:
默认的动态锚: jsPlumb提供一个动态的锚,定名为“AutoDefault”默认位置有:TopCenter,RightMiddle,BottomCenter和LeftMiddle
动态锚和可拖动的连接是可以进行互操作的,当你开始拖动连接或释放它时,jsPlumb会锁定一个动态的锚的位置,您可以在界面上看到链接锚点的切换变化。 4. 连接器、端点,覆盖物(Connector, Endpoint & Overlay Definitions)
在我们讨论连接器、终点和覆盖物之前,需要提醒的是:你需要定义一个连接器,端点或覆盖,您必须使用一个“定义”,而不是直接构建一个,这个定义可以是一个字符串,它指定你需要创建的对象。
或者您需要构件的对象的属性名组成的数组,您可以通过其构造函数来创建,例如
也有三个参数的方法,可以让你指定两套参数,jsPlumb会自动为你合并,例如
5. 连接器(Connectors) 链接的线,实际上是界面上的各个元素的链接线,jsPlumb有三条连接器实现,一条直线、Bezier曲线和”流程图”连线,默认的连接线是贝塞尔曲线,您可以有选择的设置一个链接器,可以通过设置“connector”来定义一个连接线,或者在添加端点时设置连接线,如果您没有为connector设置一个值,那么他会用他的默认值”Default” 三种链接的定义语法类似 贝塞尔曲线:
贝塞尔曲线提供了两个端点之间的立方体路径,它支持一个构造函数参数, curviness -可选,默认为150,这定义的锚点位于贝塞尔曲线的控制点,以像素为单位的距离,但这并不意味着你的连接器会穿过从你的曲线到这个距离的点,这仅是一个标识而已。 直线:直连绘制直线的两个端点之间。 没有构造函数的参数支持,使用参数endpointStyle定义连接样式或添加端点时定义连接线样式
流程图:这种类型的连接器,绘制一系列垂直或水平段组成的连接 - 经典的流程图,支持一个单一的构造函数参数 存根 -这是最小长度,以像素为单位,从端点发出的初始存根。 此参数是可选的,默认为30像素 6. 端点类型(Endpoint Types)
一个端点的UI组件,标志着一个锚的位置,是连接器连接的点,jsPlumb有三个端点实现,点、矩形和图形,你可以指定端点的属性,在jsPlumb.connect时指定属性,或者jsPlumb.Addendpiont时指定,或者设置jsPlumbde target时设定属性,语法可参照connector。 三个可用的端点类型,他们的构造函数参数如下: 点端点(Dot Endpoint): 此端点在屏幕上画一个点。 它支持一个构造函数参数: 半径 -可选,默认为10个像素。 定义点的半径 矩形端点(Rectangle Endpoint):
绘制一个矩形。 支持的构造函数的参数是:
宽度 -可选;默认为20像素。 定义矩形的宽度。 高度 -可选,默认为20个像素。 定义矩形的高度。 图片端点(Image Endpoint):
从一个给定的的URL绘制图像。 此端点支持一个构造函数的参数: SRC -必需的。 指定要使用的图像的URL。
7. 覆盖物类型(Overlay Types) 覆盖界面上的链接元素,如标签或箭头等,jsPlumb有四个默认值: Arrow:可配置的箭头,放在两个点的连接线上,你可以控制箭头的长度和宽度, 转折点:是一个折回点,方向点(允许值是1和-1,意味着是点的链接方向) Label:在点的连接器上的可配置的标签 PlainArrow:一个三角形箭头,没有折回点 包含总结汇报、高中教育、农林牧渔、行业论文、求职职场、表格模板、教学研究、经管营销、外语学习以及jsplumb介绍等内容。本文共5页
相关内容搜索sponsored links
jsPlumb插件做一个模仿viso的可拖拉流程图
这是我第一次写博客,心情还是有点小小的激动!这次主要分享的是用jsPlumb,做一个可以给用户自定义拖拉的流程图,并且可以序列化保存在服务器端。
我在这次的实现上面做得比较粗糙,还有分享我在做jsPlumb流程图遇到的一些问题。
制作流程图用到的相关的脚本:
1 &script src="&%= ResolveUrl("~/resources/jquery/jquery-1.11.1.min.js")%&" type="text/javascript"&&/script&
&script src="&%= ResolveUrl("~/resources/jquery-ui-1.10.4/js/jquery-ui-1.10.4.min.js") %&" type="text/javascript"&&/script&
&script src="&%= ResolveUrl("~/resources/jquery-plugins/jquery.jsPlumb-1.6.2-min.js") %&" type="text/javascript"&&/script&
jsPlumb-1.6.2-min.js在官网上下载,这里用得是最新版本。jquery-1.11.1.min.js等脚本百度上都能找到,这里就不多说了。
css样式在官网里也可以搜到,这里我就贴出来。
box-shadow: 2px 2px 19px #aaa;
-o-box-shadow: 2px 2px 19px #aaa;
-webkit-box-shadow: 2px 2px 19px #aaa;
-moz-box-shadow: 2px 2px 19px #aaa;
-moz-border-radius: 0.5em;
border-radius: 0.5em;
opacity: 0.8;
filter: alpha(opacity=80);
border: 1px solid #346789;
width: 150px;
/*line-height: 40*/
text-align: center;
z-index: 20;
position: absolute;
background-color: #eeeeef;
color: black;
padding: 10px;
font-size: 9pt;
cursor: pointer;
height: 50px;
line-height: 50px;
border-radius: 25em;
.node:hover {
box-shadow: 2px 2px 19px #;
-o-box-shadow: 2px 2px 19px #;
-webkit-box-shadow: 2px 2px 19px #;
-moz-box-shadow: 2px 2px 19px #;
opacity: 0.8;
filter: alpha(opacity=80);
&这里还有提到一点,jsPlumb官网上的api全是英文的,博主我从小英文就不好,所以看里面的doc非常费劲,一般都是一边开着金山翻译,
一边看着文档,英语好的略过这段。
言归正传,现在开始我们的jsPlumb流程图制作,下面先附上流程图。
根据客户的要求,我们要完成的功能点有以下几点:
1.支持将左边的div层拖拉到右边中间的层,并且左边同一个div拖拉没有次数限制,如果只能拖拉一次,做这个东西就没有什么意义了。
2.拖拉到中间的div层可以拖动,拖动不能超过中间div的边框。
3.拖动到中间的层,四周能有4个endpoint点,可供客户连线。
4.能支持删除多余的div的功能。
5.支持删除连接线。
6.能双击修改流程图的文字。
7.能序列化保存流程图。
下面我们根据功能开始制作:
1.拖拉jsPlumb其实是提供draggable方法,和droppable方法官网里有介绍, 但是我这里用得是jquery里的draggable()和droppable()。
1 &div id="left"&
&div class="node radius" id="node1"&开始&/div&
&div class="node" id="node2"&流程&/div&
&div class="node" id="node3"&判断&/div&
&div class="node radius" id="node4"&结束&/div&
&div id="right"&
&p&拖拉到此区域&/p&
&div id="save"&
&input type="button" value="保存" onclick="save()" /&
$("#left").children().draggable({
helper: "clone",
scope: "ss",
helper:"clone"表示,scope:"ss"是一个标识为了判断是否可以放置,主要用于droppable方法里面也设置这个标识来判断拖放到的地方,
除非两个都不写scope,可以随便拖放,但是会有一个问题,每次我从左边拖东西到右边,我再拖到的时候就会有div拖到不了,所以最好设置
scope:"//里面的值随便,只是一个标识"。
下面是完整的拖放:
1 $("#left").children().draggable({
helper: "clone",
scope: "ss",
$("#right").droppable({
scope: "ss",
drop: function (event, ui) {
var left = parseInt(ui.offset.left - $(this).offset().left);
var top = parseInt(ui.offset.top - $(this).offset().top);
var name = ui.draggable[0].
switch (name) {
case "node1":
var id = "state_start" +
$(this).append('&div class="node" style="border-radius: 25em"
id="' + id + '" &' + $(ui.helper).html() + '&/div&');
$("#" + id).css("left", left).css("top", top);
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
jsPlumb.draggable(id);
$("#" + id).draggable({ containment: "parent" });
doubleclick("#" + id);
case "node2":
id = "state_flow" +
$(this).append("&div class='node' id='" + id + "'&" + $(ui.helper).html() + "&/div&");
$("#" + id).css("left", left).css("top", top);
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, hollowCircle);
jsPlumb.draggable(id);
$("#" + id).draggable({ containment: "parent" });
doubleclick("#" + id);
case "node3":
id = "state_decide" +
$(this).append("&div class='node' id='" + id + "'&" + $(ui.helper).html() + "&/div&");
$("#" + id).css("left", left).css("top", top);
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, hollowCircle);
jsPlumb.draggable(id);
$("#" + id).draggable({ containment: "parent" });
doubleclick("#" + id);
case "node4":
id = "state_end" +
$(this).append('&div class="node" style="border-radius: 25em"
id="' + id + '" &' + $(ui.helper).html() + '&/div&');
$("#" + id).css("left", left).css("top", top);
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
jsPlumb.draggable(id);
$("#" + id).draggable({ containment: "parent" });
doubleclick("#" + id);
怎么样把左边的层到右边的层,我的做法是这样的:
1 $(this).append('&div class="node" style="border-radius: 25em"
id="' + id + '" &' + $(ui.helper).html() + '&/div&');
做到这里会有人奇怪,怎么做到左边能拉无数次append到右边,id这样不会冲突吗?我就在外面var i=0; 当有元素拖放到右边的div时,i++;
然后var id="state_start"+i;拼接起来,这样你的id就不会一样了。
然后再设置div的left和top:
drop: function (event, ui) {
var left = parseInt(ui.offset.left - $(this).offset().left);
var top = parseInt(ui.offset.top - $(this).offset().top);
$("#" + id).css("left", left).css("top", top);
2.拖拉到中间的div层可以拖动,拖动不能超过中间div的边框:
jsPlumb.draggable(id);$("#" + id).draggable({ containment: "parent" });
3.拖动到中间的层,四周能有4个endpoint点,可供客户连线:
这个功能是本文的重点,如何通过jsPlumb初始化端点和构造端点(endpoint)。
3.1 初始化端点样式设置:主要设置一些基本的端点,连接线的样式,里面的属性不设置,默认使用默认值
//基本连接线样式
var connectorPaintStyle = {
lineWidth: 4,
strokeStyle: "#61B7CF",
joinstyle: "round",
outlineColor: "white",
outlineWidth: 2
// 鼠标悬浮在连接线上的样式
var connectorHoverStyle = {
lineWidth: 4,
strokeStyle: "#216477",
outlineWidth: 2,
outlineColor: "white"
16 var hollowCircle = {
endpoint: ["Dot", { radius: 8 }],
//端点的形状
connectorStyle: connectorPaintStyle,//连接线的颜色,大小样式
connectorHoverStyle: connectorHoverStyle,
paintStyle: {
strokeStyle: "#1e8151",
fillStyle: "transparent",
radius: 2,
lineWidth: 2
//端点的颜色样式
//anchor: "AutoDefault",
isSource: true,
//是否可以拖动(作为连线起点)
connector: ["Flowchart", { stub: [40, 60], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }],
//连接线的样式种类有[Bezier],[Flowchart],[StateMachine ],[Straight ]
isTarget: true,
//是否可以放置(连线终点)
maxConnections: -1,
// 设置连接点最多可以连接几条线
connectorOverlays: [["Arrow", { width: 10, length: 10, location: 1 }]]
3.2 构造端点(endpoint):怎样将端点添加到div的四周?
jsPlumb.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle);
jsPlumb.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle);
通过jsPlumb.addEndpoint(a,b,c)里面有三个参数,a:要添加端点的div的b:设置端点放置的位置("TopCenter","RightMiddle","BottomCenter","LeftMiddle")
四个初始位置;c:端点和连接线的样式。b,c(可选).
添加多个端点:jsPlumb.addEndpoints(a,b,c)三个参数 c(可选),a:要添加端点的div的b:含端点的构造函数参数的对象列表;
举个例子:
4.支持删除多余的div的功能:
有时候拖拉div经常会发生拖多了等问题,所有需要删除功能。我要做的删除效果是:鼠标放到div上面,div的会出现一个红色的删除图标,鼠标移走就消失。如下图:
我是通过以下代码实现的:
$("#right").on("mouseenter", ".node", function () {
$(this).append('&img src="../../resources/images/close2.png"
style="position:" /&');
if ($(this).text() == "开始"
$(this).text() == "结束") {
$("img").css("left", 158).css("top", 0);
$("img").css("left", 158).css("top", -10);
$("#right").on("mouseleave", ".node", function () {
$("img").remove();
我想在这里大家都有疑问吧,为什么用on()事件委托。因为&img /&是后添加进来的元素,前面页面已经完成了初始化,所以你用$("img")根本找不到这个元素,
因为img是在页面初始化后,才添加的元素。这里就提到了live()为什么不用这个,jquery1.7.2才有这个方法,这里用的是jquery1.11.1 已经没有live()方法了,
取而代之的是on()方法。(live()有许多缺点,所以在新的版本被摒弃了)
后面删除比较简单:
$("#right").on("click", "img",function () {
if (confirm("确定要删除吗?")) {
jsPlumb.removeAllEndpoints($(this).parent().attr("id"));
$(this).parent().remove();
注明:这里我遇到一个问题,你删除了那个div,你还得把它周围的4个端点(endpoint)删除,这个问题刚开始我想了很多,一直没做出来,后来去jsPlumb官网查看相关的资料,
发现jsPlumb提供一个方法能删除div四周的端点。方法如下:
jsPlumb.removeAllEndpoints($(this).parent().attr("id"));//删除指定id的所有端点
5.支持删除连接线:
jsPlumb.bind("click", function (conn, originalEvent) {
if (confirm("确定删除吗?
jsPlumb.detach(conn);
6.&能双击修改流程图的文字:
function doubleclick(id) {
$(id).dblclick(function () {
var text = $(this).text();
$(this).html("");
$(this).append("&input type='text' value='" + text + "' /&");
$(this).mouseleave(function () {
$(this).html($("input[type='text']").val());
7.能序列化保存流程图:
我的思路是这样的,将中间div里所有的"流程图div信息和连接线两端的信息"保存到数组里,然后序列化成json数据,通过ajax传到asp.net 后台,将json写入到txt文档里保存到服务器端。
(其实保存到数据库里是最好的,后面会考虑保存到数据库),下次展示页面的时候,只要读取txt文档里的json,然后再转成泛型集合。
将页面上的div信息,和连线信息转成json跳转到ajax.aspx页面:
function save() {
var connects = [];
$.each(jsPlumb.getAllConnections(), function (idx, connection) {
connects.push({
ConnectionId: connection.id,
PageSourceId: connection.sourceId,
PageTargetId: connection.targetId,
SourceText: connection.source.innerText,
TargetText: connection.target.innerText,
var blocks = [];
$("#right .node").each(function (idx, elem) {
var $elem = $(elem);
blocks.push({
BlockId: $elem.attr('id'),
BlockContent: $elem.html(),
BlockX: parseInt($elem.css("left"), 10),
BlockY: parseInt($elem.css("top"), 10)
var serliza = JSON.stringify(connects) + "&" + JSON.stringify(blocks);
type: "post",
url: "ajax.aspx",
data: { id: serliza },
success: function (filePath) {
window.open("show-flowChart.aspx?path=" + filePath);
ajax.aspx页面将前台传过来的json保存到服务器端,并跳转至 show-flowChart.aspx:
protected void Page_Load(object sender, EventArgs e)
if (!IsPostBack)
string str = Request["id"];
string filePath = Server.MapPath("~/prototype/project-reply")+"\\json"+DateTime.Now.ToString("yyyyMMddhhmmss")+".txt";
WriteToFile(filePath,str,false);
//Response.Redirect("show-flowChart.aspx?path="+filePath);
Response.Write(filePath);
public static void WriteToFile(string name, string content, bool isCover)
FileStream fs = null;
if (!isCover && File.Exists(name))
fs = new FileStream(name, FileMode.Append, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
sw.WriteLine(content);
sw.Flush();
sw.Close();
File.WriteAllText(name, content, Encoding.UTF8);
if (fs != null)
fs.Close();
&show-flowChart.aspx页面:
1 protected void Page_Load(object sender, EventArgs e)
if (!IsPostBack)
string str = Request["path"];
StreamReader sr = new StreamReader(str);
string jsonText = sr.ReadToEnd();
List&JsPlumbConnect& list = new JavaScriptSerializer().Deserialize&List&JsPlumbConnect&&(jsonText.Split('&')[0]);
List&JsPlumbBlock& blocks = new JavaScriptSerializer().Deserialize&List&JsPlumbBlock&&(jsonText.Split('&')[1]);
string htmlText = "";
string conn = "";
if (blocks.Count & 0)
foreach (JsPlumbBlock block in blocks)
if(block.BlockContent=="开始"block.BlockContent=="结束")
htmlText += "&div class='node radius' id='" + block.BlockId + "'style='left:"+block.BlockX+"top:"+block.BlockY+"' &" + block.BlockContent + "&/div&";
htmlText += "&div class='node' id='" + block.BlockId + "'style='left:" + block.BlockX + "top:" + block.BlockY + "' &" + block.BlockContent + "&/div&";
foreach (JsPlumbConnect jsplum in list)
conn += "jsPlumb.connect({ source: \"" + jsplum.PageSourceId + "\", target: \"" + jsplum.PageTargetId + "\" }, flowConnector);";
Literal1.Text = htmlT
string script = "jsPlumb.ready(function () {" + conn + "});";
ClientScript.RegisterStartupScript(this.GetType(), "myscript", script, true);
以及两个用到的类JsPlumbConnect类和JsPlumbBlock类:
1 /// &summary&
/// 连接线信息
/// &/summary&
public class JsPlumbConnect
public string ConnectionId { get; set; }
public string PageSourceId { get; set; }
public string PageTargetId { get; set; }
public string SourceText { get; set; }
public string TargetText { get; set; }
/// &summary&
/// 流程图的所有div
/// &/summary&
public class JsPlumbBlock
/// &summary&
/// div Id
/// &/summary&
public string BlockId { get; set; }
/// &summary&
/// div里面的内容
/// &/summary&
public string BlockContent { get; set; }
public int BlockX { get; set; }
public int BlockY { get; set; }
转载请注明出处,谢谢!
附件下载地址:/s/1jGC8XM2
小伙伴们啊,我JS真的是个渣渣,所以总想要偷懒,于是为了实现效果就把tab插件给改了(各位大神轻拍啊,我是小白,很纯洁滴,小心脏也很脆弱)……
最近做的项目为了考虑以后的移动设备兼容性,所以用了Bootstrap.首页有一个需要鼠标点击不一样的按钮固定位置图层内容变化的效果(我描述清楚了吗Orz……),如下图:
对于其中可能会出现的几种错误做下说明: 1.当你的hadoop已经安装完毕,第二天打开的时候start-all.sh之后也许就会出现各种各样的问题.要学会查看日志.vim /home/xinxin/hadoop/logs ,一般情况下查看启动情况,首先在hadoop目录下jps,如果显示启动的项数目少于6个,就要去检查log里相应的日志项: Secondar ...
以下是本周移动开发技术周报的推荐资料: 工具: 使用Overshare让你的分享更多元:Overshare是一套强化的iOS分享库,让你的分享不仅可以使用iOS自带的选项,也可以增加其他的第三方网站或是应用去分享,另外也提供了多帐号管理让你更容易的去分享信息到不同的平台上. 使用AnalyticsKit让你更容易去发现移动应用潜在问题:AnalyticsKi ...
var request = require('request') var url = '/home/xman/data/superload' var cookie = '你登录百度后的cookie' var options = { method: &GET&, url: url, qs: { &qu ...
在线演示 本地下载 (代码太多请查看原文) 加班,加班加班,我爱加班··· 我已经疯了,哦也. 这次发一个刚接触boot的时候用boot做的表单验证,我们扩展一下tooltip的插件,让他可以换颜色. 其实挺简单的,主要是考究代码阅读的能力. boot的代码写的很简单,能省略“;”的地方就省略掉了,而且他的闭包也很有意思 +function($){ }(jQ ...}

我要回帖

更多关于 悬浮鼠标 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信