问题背景

在工作中有个需求需要画一幅“树图”,本想使用echarts进行绘制的。奈何echarts的label中不支持formatter html,即html文本的渲染。故为了使图的节点更具有交互性,这里选择使用jointjs。

问题解决

jointjs是一个js图表库,其可在浏览器的网页中创建可交互的图表工具,它依赖于js与SVG。(这个在网页渲染后可以在浏览器按F12查看页面元素看到)

基本使用

关于jointjs的使用以及在jointjs元素中使用html这些在官方的文档中已经很详细了。我这里也只当加一下自己的理解翻译了。首先还是来回顾下它的基本使用吧。

  1. 配置
    这个主要就是配置下jointjs的相关js库,官方网页有下载的资源和示例。如果这里还想用bootstrap,可以将其也包含进来。最后将这些资源放入到html的head标签里面。我这里盗用下官方的图吧。
  2. 画图
    下来就是在网页中画图了。jointjs画图的步骤还是很人性化的。其跟我们平时画流程图的步骤一样,准备纸张,在纸张里画好对应的节点图,然后将图形之间连线。jointjs的步骤也是如此。下来就看看官方的hello world吧。其代码如下:
<!DOCTYPE html>
<html>
<head><link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.css" />
</head>
<body><!-- content -->// 在网页中定义一个盒子<div id="myholder"></div><!-- dependencies --><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.js"></script><!-- code --><script type="text/javascript">// 定义一个图表模板。我这里理解应该是jointjs想将纸上面的图表作为一个整体图表模板进行管理。官方文档也说了在纸张上画的图形元素都需要进行加入到模板里才能在网页上渲染出来var graph = new joint.dia.Graph;
// 定义一张纸。包括纸的背景颜色、长宽之类的。只有有了纸,我们才能在上面画画var paper = new joint.dia.Paper({el: document.getElementById('myholder'),//这里相当于将graph图表模板放入到纸张里面了。纸张到时候就会渲染graph里面的图形元素,我们只需要将想画的图形元素放入graph模板里就可以了model: graph,width: 600,height: 100,gridSize: 1});
// 在纸上面画一个矩形。jointjs已为我们定义好了一些矩形、圆角矩形、三角形等形状供选择,我们可以通过“new一个矩形的对象”来在纸上画一个矩形var rect = new joint.shapes.standard.Rectangle();// 矩形的位置。以纸张左上角为原点,相当于以纸张左上角为原点的y轴箭头向下、x轴箭头向右的二维坐标系中画图形rect.position(100, 30);// 矩形的长宽rect.resize(100, 40);// 矩形的属性。包括填充色、里面的文字、字体的颜色等rect.attr({body: {fill: 'blue'},label: {text: 'Hello',fill: 'white'}});// 最后别忘了加入到图表模板中rect.addTo(graph);// 定义另一个矩形。这里用了colone函数,clone了上一个矩形的部分属性,如长、宽等。var rect2 = rect.clone();rect2.translate(300, 0);rect2.attr('label/text', 'World!');// 加入到图表模板中rect2.addTo(graph);//定义一条连接线,将两个矩形连接起来。var link = new joint.shapes.standard.Link();//连接线的起点link.source(rect);// 连接线的终点link.target(rect2);// 也添加到图表模板中link.addTo(graph);</script>
</body>
</html>

代码生成的效果如下,截一张官方图放这。

jointjs画图的整个过程走下来,跟我们在纸上画流程图的过程是一样的。

在jonitjs元素中使用html

这个过程其实相当于要给纸张里面的图形元素加上html元素,比如按钮之类的。比如我们要给上面hello_world中的矩形里面加入一个按钮。不幸的是jointjs中并没有那种现成的可利用的个性化定制图形。不过幸运的是jointjs给了我们足够的接口,让我们可以随心所欲的定义自己需求的图形元素(这里感觉跟Android中的自定义view很像)。好了,废话不多说,先看官方教程吧,我这里也权当翻译吧。

(function() {// 创建图表模板var graph = new joint.dia.Graph;// 定义纸张var paper = new joint.dia.Paper({ el: $('#paper-html-elements'), width: 650, height: 400, gridSize: 1, model: graph });// Create a custom element.
// 主要是这里,要自定义一个从无到有的html类型图形元素的母板,就像hello world示例的基本的矩形图形
// ------------------------
// jointjs给了最初始的html母板,并且母板的初始形状为矩形joint.shapes.html = {};joint.shapes.html.Element = joint.shapes.basic.Rect.extend({defaults: joint.util.deepSupplement({type: 'html.Element',attrs: {rect: { stroke: 'none', 'fill-opacity': 0 }}}, joint.shapes.basic.Rect.prototype.defaults)});// Create a custom view for that element that displays an HTML div above it.
// -------------------------------------------------------------------------
// 这一步就是在上面创建的母板里自定义可交互的html。从下面看里面包含了按钮button、label、span、单选框select、输入框input的元素joint.shapes.html.ElementView = joint.dia.ElementView.extend({template: ['<div class="html-element">','<button class="delete">x</button>','<label></label>','<span></span>', '<br/>','<select><option>--</option><option>one</option><option>two</option></select>','<input type="text" value="I\'m HTML input" />','</div>'].join(''),
// 下面这个函数则是初始化自定义图形里面的html元素的交互情况以及实时更新html里元素的位置。例如按钮点击时移除一个图形元素等。initialize: function() {_.bindAll(this, 'updateBox');joint.dia.ElementView.prototype.initialize.apply(this, arguments);this.$box = $(_.template(this.template)());// 阻止纸张争夺了点击事件// Prevent paper from handling pointerdown.this.$box.find('input,select').on('mousedown click', function(evt) {evt.stopPropagation();});// This is an example of reacting on the input change and storing the input data in the cell model.// 将input输入的内容呈现到图形元素上this.$box.find('input').on('change', _.bind(function(evt) {this.model.set('input', $(evt.target).val());}, this));// 监听单选框值的改变事件,并将单选框元素的显示值设为点击的值this.$box.find('select').on('change', _.bind(function(evt) {this.model.set('select', $(evt.target).val());}, this));this.$box.find('select').val(this.model.get('select'));this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));// Update the box position whenever the underlying model changes.// 当图形位置改变时,其里面的html位置也会改变,但它们之间的相对位置不变this.model.on('change', this.updateBox, this);// Remove the box when the model gets removed from the graph.// 移除图形元素this.model.on('remove', this.removeBox, this);this.updateBox();},render: function() {joint.dia.ElementView.prototype.render.apply(this, arguments);this.paper.$el.prepend(this.$box);this.updateBox();return this;},updateBox: function() {// Set the position and dimension of the box so that it covers the JointJS element.var bbox = this.model.getBBox();// Example of updating the HTML with a data stored in the cell model.// 将设置label的值给html里面的label元素this.$box.find('label').text(this.model.get('label'));// 将html中的span元素的值设为html中select元素的值this.$box.find('span').text(this.model.get('select'));this.$box.css({width: bbox.width,height: bbox.height,left: bbox.x,top: bbox.y,transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)'});},// 移除图形removeBox: function(evt) {this.$box.remove();}});
// 自定义的图形模板已经创建好了。下面的操作跟hello world里的一样,即在纸张里画两自定义图形,并创建一条连接线将其连接起来
// Create JointJS elements and add them to the graph as usual.
// -----------------------------------------------------------var el1 = new joint.shapes.html.Element({position: { x: 80, y: 80 },size: { width: 170, height: 100 },label: 'I am HTML',select: 'one'});var el2 = new joint.shapes.html.Element({position: { x: 370, y: 160 },size: { width: 170, height: 100 },// 给自定义图形中的html的label设值label: 'Me too',select: 'two'});// 创建连接线var l = new joint.dia.Link({source: { id: el1.id },target: { id: el2.id },attrs: { '.connection': { 'stroke-width': 5, stroke: '#34495E' } }});// 将几个图形元素加入到图表模板中graph.addCells([el1, el2, l]);}())

官方文档中还有一个css静态资源文件,用来对自定义的html中各标签进行位置、背景、颜色等的设置,这里就不写了.感觉官方举的例子有些冗余了。下面是我创建了一个自定义图形中只包含一个按钮的示例。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" type="text/css" href="joint.css" /><link rel="stylesheet" type="text/css" href="bootstrap.min.css" /><script src="jquery.js"></script><script src="lodash.js"></script><script src="backbone.js"></script><script src="joint.js"></script><!-- 包含了bootstrap --><script src="bootstrap.min.js"></script><style>#paper-html-elements {position: relative;border: 1px solid gray;display: inline-block;background: transparent;overflow: hidden;}#paper-html-elements svg {background: transparent;}#paper-html-elements svg .link {z-index: 2;}.html-element {position: absolute;background: #3498DB;/* Make sure events are propagated to the JointJS element so, e.g. dragging works.*/pointer-events: none;-webkit-user-select: none;border-radius: 4px;border: 2px solid #2980B9;box-shadow: inset 0 0 5px black, 2px 2px 1px gray;padding: 5px;box-sizing: border-box;z-index: 2;}.html-element button {/* Enable interacting with inputs only. */pointer-events: auto;}.html-element button.viewlog {color: white;line-height: 15px;text-align: middle;position: absolute;padding: 0;margin: 0;font-weight: bold;cursor: pointer;}.html-element label {color: #333;text-shadow: 1px 0 0 lightgray;font-weight: bold;}</style>
</head>
<body>
<div id="myholder"></div>
<script type="text/javascript">(function() {var graph = new joint.dia.Graph;var paper = new joint.dia.Paper({ el: $('#myholder'), width: 650, height: 400, gridSize: 1, model: graph });joint.shapes.html = {};joint.shapes.html.Element = joint.shapes.basic.Rect.extend({defaults: joint.util.deepSupplement({type: 'html.Element',attrs: {rect: { stroke: 'none', 'fill-opacity': 0 }}}, joint.shapes.basic.Rect.prototype.defaults)});joint.shapes.html.ElementView = joint.dia.ElementView.extend({template: ['<div class="html-element">','<label></label>','<div style="margin-right: 10px;text-align: center;"><button type="button" class="viewlog btn btn-success" title="一个小按钮" data-container="body" data-toggle="popover" data-placement="right" data-content="右侧的 Popover 中的一些内容">查看详情</button></div>','</div>'].join(''),initialize: function() {_.bindAll(this, 'updateBox');joint.dia.ElementView.prototype.initialize.apply(this, arguments);this.$box = $(_.template(this.template)());this.$box.find('.viewlog').on('click', function (e) {// 这里面添加按钮viewlog的点击事件等alert("啊哈哈");});this.model.on('change', this.updateBox, this);this.updateBox();},render: function() {joint.dia.ElementView.prototype.render.apply(this, arguments);this.paper.$el.prepend(this.$box);this.updateBox();return this;},updateBox: function() {var bbox = this.model.getBBox();this.$box.find('label').text(this.model.get('label'));this.$box.css({width: bbox.width,height: bbox.height,left: bbox.x,top: bbox.y,transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)'});},});var el1 = new joint.shapes.html.Element({position: { x: 80, y: 80 },size: { width: 170, height: 60 },label: 'I am HTML'});var el2 = new joint.shapes.html.Element({position: { x: 370, y: 160 },size: { width: 170, height: 60 },label: 'Me too'});var l = new joint.dia.Link({source: { id: el1.id },target: { id: el2.id },attrs: { '.connection': { 'stroke-width': 5, stroke: '#34495E' } }});graph.addCells([el1, el2, l]);}());$(function (){//使用了bootstrap的popover$("[data-toggle='popover']").popover();});
</script>
</body>
</html>

结果如下:

总结

可以看到,在jointjs的图形中使用html本质上其实就是根据jointjs提供的接口自定义自己的图形,然后在纸张上进行画图、连线等。另外渲染好的图在浏览器中查看元素时,可以看到就是一些SVG和html、js。也正好印证了jointjs的自我介绍那句话。

在JointJS元素中使用html相关推荐

  1. JointJS入门实例01-补充第一篇在JOINTJS元素中使用HTML

    1.1 简介 很多时候,您可能希望在JointJS图表中使用HTML输入或其他HTML元素.本实例中使用的技术是创建一个自定义视图,用于呈现HTML并处理与HTML的交互.一种不同的方法可能是使用 f ...

  2. JointJS入门实例01-在JOINTJS元素中使用HTML

    1.1 简介   很多时候,您可能希望在JointJS图表中使用HTML输入或其他HTML元素.本实例中使用的技术是创建一个自定义视图,用于呈现HTML并处理与HTML的交互.一种不同的方法可能是使用 ...

  3. html 中设置样式方式,在html元素中设置css样式的方式是什么

    如果我们要在HTML元素中设置CSS样式,那么我们就需要在元素中设置"id" 和 "class"选择器. (推荐教程:CSS教程) 下面我们来分别说一下id选择 ...

  4. pythonlambda内判定_python lambda和列表推导式判断列表中元素中指定值得max

    今天提了个需求 说有一个商品列表 需要提取中元素中金额的最大值 废话不多说直接上码 # 假如现在有个商品列表 class ProductSeatMock(object): def __init__(s ...

  5. iOS上的jQuery.on()冒泡事件绑定 以及 iOS绝对定位元素中的输入框

    来:http://www.bubuko.com/infodetail-1029287.html 上周遇到两个坑. 一是jQuery的on方法 事件冒泡,在iOS中有问题. $("body&q ...

  6. 如何限制HTML5“数字”元素中的可能输入?

    本文翻译自:How can I limit possible inputs in a HTML5 "number" element? For <input type=&quo ...

  7. ​​​​​​​​​​​​​​使用dom方式遍历文档||获取元素||从元素中获取数据

    使用dom方式遍历文档 获取元素 根据id查询元素getElementById 根据标签获取元素getElementsByTag 根据class获取元素getElementsByClass 根据属性获 ...

  8. 怎么将多个html组合_技巧分享之在HTML元素中添加逼真阴影的教程

    添加一个简单的阴影 让我们为投影准备一个简单的HTML元素: 然后添加CSS: 输出结果是三个框,通过调用每个框的ID可以很容易地放置阴影.要添加阴影,让我们将属性box-shadow赋予框1: 我们 ...

  9. 行内元素中去掉文字的上下间距,使得文字所在元素的高度同字体高度一致的方法...

    之前在p这类块元素中的文字,给line-hight=1;就可以去掉文字自带的上下间距, 像这样: 最近突然发现这个方法在行内块和块元素上好使,可当用在span或者a这类内联元素上都不好使,除了转为块元 ...

最新文章

  1. 18.绝对路径和相对路径
  2. python好学-html和Python哪个好学?
  3. 大一写的C课程设计(图书馆管理系统)
  4. 图标出问题_同是Office365,为什么你的软件图标还是旧版的?
  5. Java基本语法(12)--分支结构if-else
  6. 阿里云服务器安装JDK指南
  7. C/C++:Windows编程—代码实现IE保护模式的关闭和开启
  8. 2012年6月份第4周51Aspx源码发布详情
  9. 几张图说明男女之间的秘密(ZT)
  10. javascript 的线程问题
  11. 上传本地项目到gitee_使用git将本地代码上传到gitee远程仓库
  12. 极大似然估计法(Maximum likelihood estimation, MLE)
  13. CSDN-怎么设置被粉丝关注之后的自动回复
  14. 解决桥接模式连接虚拟机的问题
  15. Chaosblade 混动工程之网络延迟实践
  16. PhpStorm 2018 最新激活码 license server
  17. omi html转义,特殊字符读法
  18. C++ 多个指针指向同一个对象
  19. 防泄密-工业自动化控制行业源代码防泄密以及技术文档防泄密解决方案
  20. p标签和超链接的认识

热门文章

  1. 奋斗吧,程序员——第四十四章 八百里分麾下炙,五十弦翻塞外声
  2. 计划策略之10 (一)
  3. Away3D 基础5 - 3D基本元素(3)
  4. 将光驱文件拷入linux系统方法
  5. Freehand做稿和输出,有哪些好的建议吗
  6. word中给图表自动编号时出现的“题注或页码中不含章节编号”的问题
  7. 高德地图Android自定义路线规划的简单实现
  8. iwebshop index.php,iwebshop源码剖析记录点滴
  9. X3D 与 HTML5
  10. 计算机专业排名等级,计算机软件专业排名