携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
前言
上一篇文章中,讲了maxGraph中修改样式的几种方式,有了这些知识储备,我们已经可以完成一些基本的修改节点、修改连线样式的自定义需求啦。
而这篇文章,则会着重从几个更具体的“奇葩”需求出发,进行实战。笔者会讲一些自己开发需求的过程中遇到的坑以及一些优化方法。
文本换行
换行相关CSS属性的介绍
- 关于
word-wrapword-breakwrap-space这三个属性的区别,有很多博客讲的很详细了,大家可以自行搜索阅读,本文不再赘述。以下将以mxGraph内部的属性设置为主,讲解mxGraph内应该如何设置文本换行。
通过mxConstants.STYLE_WHITE_SPACE 和 WORD_WRAP
// 需要制定修改的样式表
const style = graph.getStylesheet().getDefaultVertexStyle(); style[mxConstants.STYLE_WHITE_SPACE] = "wrap"; // 默认值是 "nowrap"
// 直接赋值给 mxConstants
mxConstants.WORD_WRAP = "break-word"; // 默认值是 "normal"
缺陷:
- 输入中文的时候可以正常换行。但有一个bug,假如输入的长文本是连续的数字/字母,文本只能在有空格的位置才能换行。
- 如下图所示,左边两个是汉字 或者 带空格的单词组合,换行正常;右边两个长文本是连续的数字/字母,换行失效了。
- 原因: 需要使用
word-break:break-all;才能打断连续的数字/字母,但是mxGraph中没有内置word-break属性 - 假如你的产品经理要求连续长文本也能得换行,那该咋办呢? 由此引入修改节点样式的另一个方法。
通过mxGraph.prototype.setHtmlLabels(),设置word-break:break-all
// 第一步:调用该API( garph 为对应代码中 mxGrap h的实例,以下同)
graph.setHtmlLabels(true);
// 第二步:设置节点的文本是,使用 html 形式,并且写入 'word-break:break-all'
// vertex 为某节点
vertex.value = `<div style='word-break:break-all'>` + 'veryverylonggggggggggggggg' + '</div>';
缺陷:
- 当我们去获取节点的value时,拿到的也是这串 html 标签的字符串。意味着我们想要拿到
veryverylonggggggggggggggg的话,需要从"<div style='word-break:break-all'>veryverylonggggggggggggggg</div>"中截取 - 如果是画布信息需要储存在后端,那么这一串html标签的字符串,都需要发送给后端。真正的数据部分夹在了html标签里发送给后端,明显很不合理。
- 所以第二种方式能满足需求,但仍然不够完美。
最终方案:通过AOP装饰函数,复写mxGraph源码中的一个设置节点基础css的方法
mxSvgCanvas2D.prototype.getTextCss()该返回一个节点基本样式的css字符串,该字符串会被设置为节点的基础css样式,即使某些css字段并不在mxConstants中。感兴趣的朋友可以去mxGraph包中的build.js里去搜索这个方法看一看。- 那么采用AOP装饰函数的思想,在这个方法的基础上添加我们需要自定义的css字段
- utils.js :定义一个AOP装饰函数工具
// fn 为原函数,afterFn为我们自定义的额外函数 export const after = (fn, afterFn) => { return function () { // 调用一次原函数,并拿到返回值,也就是mxGraph本身定义的节点基础 css样式 的字符串 const ret = fn.apply(this, arguments); // 将以上的 css 字段入参给我们自定义的函数处理后,再 return 出去 return afterFn(ret); }; };- mxgraph.vue :在自己的mxgraph组件中,改写
mxSvgCanvas2D.prototype.getTextCss
import { after } from '....'; // r仍然需要设置html label graph.setHtmlLabels(true); // fn 为原函数,afterFn为我们自定义的额外函数 mxSvgCanvas2D.prototype.getTextCss = after(mxSvgCanvas2D.prototype.getTextCss, originCss => { // 将 word-break: break-all 直接拼在原css后面 return `${originCss}word-break: break-all;` }) - 可以看到对应文本的dom节点内,已经有了我们写入的
word-break: break-all;举一反三,也可以写入其他自定义的公共样式,规避mxConstants内置样式的限制