Widget:可视化推荐阅读编辑器
<script src="https://cdn.jsdelivr.net/npm/@logicflow/core/dist/index.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/@logicflow/core/lib/style/index.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/@logicflow/extension/dist/index.min.js"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@logicflow/extension/lib/style/index.min.css" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<body>
</body>
<script>
const { HtmlResize, dynamicGroup, DndPanel, Menu, Control, MiniMap, DynamicGroup, SelectionSelect } = Extension;
const { LogicFlow, h, BaseText } = Core;
// 暂定五种节点:主线、世界深处、约会剧情、活动剧情、手机信息
// 定义主线节点
class CommonModel extends HtmlResize.model {
initNodeData(data) {
super.initNodeData(data);
this.width = 200;
this.height = 50;
}
getTextStyle() {
const style = super.getTextStyle();
style.color = this.properties.textColor || '#aa7952';
style.fontSize = 15
return style;
}
}
class MainLineNode extends HtmlResize.view {
setHtml(rootEl) {
let node_md = this.props.model;
// node_md.properties 获取节点属性
let el = document.createElement("div");
el.className = "main-line-node node-div";
el.id = node_md.id; // html 节点绑定节点唯一ID;即可通过id 获取对应dom元素 并进行相关业务操作
el.innerHTML = "";
// 需要先把之前渲染的子节点清除掉。
rootEl.innerHTML = "";
rootEl.appendChild(el);
}
}
const MainLineBox = {
type: "main_line_node",
view: MainLineNode,
model: CommonModel,
};
// 定义世界深处节点
class WorldDeepNode extends HtmlResize.view {
setHtml(rootEl) {
let node_md = this.props.model;
let el = document.createElement("div");
el.className = "world-deep-node node-div";
el.id = node_md.id; // html 节点绑定节点唯一ID;即可通过id 获取对应dom元素 并进行相关业务操作
el.innerHTML = "";
// 需要先把之前渲染的子节点清除掉。
rootEl.innerHTML = "";
rootEl.appendChild(el);
}
}
const WorldDeepBox = {
type: "world_deep_node",
view: WorldDeepNode,
model: CommonModel,
};
// 定义约会剧情节点
class DatePlotNode extends HtmlResize.view {
setHtml(rootEl) {
let node_md = this.props.model;
let el = document.createElement("div");
el.className = "date-plot-node node-div";
el.id = node_md.id; // html 节点绑定节点唯一ID;即可通过id 获取对应dom元素 并进行相关业务操作
el.innerHTML = "";
// 需要先把之前渲染的子节点清除掉。
rootEl.innerHTML = "";
rootEl.appendChild(el);
}
}
const DatePlotBox = {
type: "date_plot_node",
view: DatePlotNode,
model: CommonModel,
};
// 定义活动剧情节点
class ActivityPlotNode extends HtmlResize.view {
setHtml(rootEl) {
let node_md = this.props.model;
let el = document.createElement("div");
el.className = "activity-plot-node node-div";
el.id = node_md.id; // html 节点绑定节点唯一ID;即可通过id 获取对应dom元素 并进行相关业务操作
el.innerHTML = "";
// 需要先把之前渲染的子节点清除掉。
rootEl.innerHTML = "";
rootEl.appendChild(el);
}
}
const ActivityPlotBox = {
type: "activity_plot_node",
view: ActivityPlotNode,
model: CommonModel,
};
// 定义手机信息节点
class PhoneInfoNode extends HtmlResize.view {
setHtml(rootEl) {
let node_md = this.props.model;
let el = document.createElement("div");
el.className = "phone-info-node node-div";
el.id = node_md.id; // html 节点绑定节点唯一ID;即可通过id 获取对应dom元素 并进行相关业务操作
el.innerHTML = "";
// 需要先把之前渲染的子节点清除掉。
rootEl.innerHTML = "";
rootEl.appendChild(el);
}
}
const PhoneInfoBox = {
type: "phone_info_node",
view: PhoneInfoNode,
model: CommonModel,
};
// 定义分组节点
class GroupModel extends dynamicGroup.model {
initNodeData(data) {
super.initNodeData(data);
// 设置默认样式
this.properties = {
...this.properties,
collapsible: false,
width: data.properties.width || 300,
height: data.properties.height || 450
}
this.collapsible = false;
}
getNodeStyle() {
const style = super.getNodeStyle();
style.fill = "transparent";
style.strokeWidth = 0;
return style;
}
// 处理高亮样式
getAddableOutlineStyle() {
const style = super.getAddableOutlineStyle();
style.stroke = "#FF9800";
style.strokeDasharray = "5 5";
return style;
}
// 节点内文本样式
// getTextStyle() {
// const style = super.getTextStyle();
// style.fontSize = 20;
// style.color = this.properties.textColor || '#aa7952'; // 修改文字颜色
// return style;
// }
}
class GroupView extends dynamicGroup.view {
// 由于分组节点没有内置自定义html方法,因此重写getShape方法,加入自定义div元素
getShape() {
const { model } = this.props
const { width, height, x, y, radius } = model
const rectSvg = super.getShape();
return h('g', {}, [
rectSvg,
h('g', {}, [
// 写入自定义内容-用于设置分组节点样式、背景图片
h('foreignObject', {
x: x - width / 2,
y: y - height / 2,
width: width,
height: height,
radius: radius,
}, [
// 注意:foreignObject内的HTML元素需要指定xhtml命名空间
h('div', {
xmlns: 'http://www.w3.org/2000/xhtml',
class: 'group-node'
})
])
])
]);
}
// getText() {
// const { model, graphModel } = this.props
// const { editConfigModel } = graphModel
// // 当 节点文本模式非 TEXT 时,不显示文本
// if (editConfigModel.nodeTextMode !== 'text') return null
// // 文本被编辑的时候,显示编辑框,不显示文本。
// if (model.state === 'TEXT_EDIT') return null
// if (model.text) {
// let draggable = false
// if (editConfigModel.nodeTextDraggable && model.text.draggable) {
// draggable = true
// }
// return h('BaseText', {
// editable: editConfigModel.nodeTextEdit && (model.text.editable ?? true),
// model: model,
// graphModel: graphModel,
// draggable: draggable,
// })
// // (
// // <
// // editable={
// // editConfigModel.nodeTextEdit && (model.text.editable ?? true)
// // }
// // model={model}
// // graphModel={graphModel}
// // draggable={draggable}
// // />
// // )
// }
// return null
// }
}
const GroupBox = {
type: "group_node",
model: GroupModel,
view: GroupView,
}
// 定义主标题
class MainTitleModel extends HtmlResize.model {
initNodeData(data) {
super.initNodeData(data);
this.width = 200;
this.height = 50;
}
getTextStyle() {
const style = super.getTextStyle();
style.fontSize = 24;
style.color = this.properties.textColor || '#aa7952';
return style;
}
}
class MainTitleNode extends HtmlResize.view {
setHtml(rootEl) {
let node_md = this.props.model;
let el = document.createElement("div");
el.className = "main-title-node title-node";
el.id = node_md.id;
el.setAttribute("data-text", node_md.text.value);
el.innerHTML = "";
// 需要先把之前渲染的子节点清除掉。
rootEl.innerHTML = "";
rootEl.appendChild(el);
}
}
const MainTitleBox = {
type: "main_title",
model: MainTitleModel,
view: MainTitleNode,
}
// 定义副标题
class SubTitleModel extends HtmlResize.model {
initNodeData(data) {
super.initNodeData(data);
this.width = 200;
this.height = 50;
}
getTextStyle() {
const style = super.getTextStyle();
style.fontSize = 20;
style.color = this.properties.textColor || '#aa7952';
// style.overflowMode = 'autoWrap'
return style;
}
}
class SubTitleNode extends HtmlResize.view {
setHtml(rootEl) {
let node_md = this.props.model;
let el = document.createElement("div");
el.className = "sub-title-node title-node";
el.id = node_md.id;
el.setAttribute("data-text", node_md.text.value);
el.innerHTML = "";
// 需要先把之前渲染的子节点清除掉。
rootEl.innerHTML = "";
rootEl.appendChild(el);
}
}
const SubTitleBox = {
type: "sub_title",
model: SubTitleModel,
view: SubTitleNode,
}
// 定义拓展阅读节点
class ExtendedReadModel extends dynamicGroup.model {
initNodeData(data) {
super.initNodeData(data);
// 设置默认样式
this.properties = {
...this.properties,
collapsible: false,
width: data.properties.width || 250,
height: data.properties.height || 150
}
this.collapsible = false;
}
getNodeStyle() {
const style = super.getNodeStyle();
style.fill = "transparent";
style.strokeWidth = 0;
return style;
}
// 处理高亮样式
getAddableOutlineStyle() {
const style = super.getAddableOutlineStyle();
style.stroke = "#FF9800";
style.strokeDasharray = "5 5";
return style;
}
}
class ExtendedReadNode extends dynamicGroup.view {
// 由于分组节点没有内置自定义html方法,因此重写getShape方法,加入自定义div元素
getShape() {
const { model } = this.props
const { width, height, x, y, radius } = model
const rectSvg = super.getShape();
return h('g', {}, [
rectSvg,
h('g', {}, [
// 写入自定义内容-用于设置分组节点样式、背景图片
h('foreignObject', {
x: x - width / 2,
y: y - height / 2,
width: width,
height: height,
radius: radius,
}, [
// 注意:foreignObject内的HTML元素需要指定xhtml命名空间
h('div', {
xmlns: 'http://www.w3.org/2000/xhtml',
class: 'extended-read-node'
})
])
])
]);
}
}
const ExtendedReadBox = {
type: "extended_read_node",
view: ExtendedReadNode,
model: ExtendedReadModel,
};
// 定义hover面板
class HoverNode {
static pluginName = 'hoverNode'
constructor({ lf, LogicFlow }) {
this.lf = lf;
this.allowHover = false; // 默认关闭
}
render(lf, container) {
this.container = container;
lf.on("node:mouseenter", ({ data }) => {
if (!this.allowHover) return;
if (data.properties.recommond || data.properties.pageUrl) {
// 创建一个div节点,将recommond内容渲染为html
let panelDiv = document.createElement("div");
panelDiv.id = "node-page-panel";
// 计算悬浮框位置
panelDiv.style.left = this.lf.getTransform().SCALE_X * (data.x + data.properties.width / 2) + this.lf.getTransform().TRANSLATE_X + "px";
panelDiv.style.top = this.lf.getTransform().SCALE_Y * (data.y - data.properties.height / 2) + this.lf.getTransform().TRANSLATE_Y + "px";
panelDiv.innerHTML = `
<button class="node-button" ${data.properties.pageUrl ? : 'disabled'}
style="${data.properties.pageUrl ? 'cursor: pointer; color: #aa7952;' : 'color: #aa79524d;'}"
onclick="window.open('${data.properties.pageUrl}')">跳转</button>
`;
this.container.appendChild(panelDiv);
panelDiv.addEventListener("mouseleave", () => {
this.container.removeChild(panelDiv);
});
let panelButton = $('.node-button')[0];
panelButton.addEventListener("mousedown", () => {
panelButton.style.backgroundImage = "url(https://patchwiki.biligame.com/images/lysk/b/ba/8wn6pkomoljy6s809xc50g5gkt6aq6l.png)";
});
panelButton.addEventListener("mouseup", () => {
panelButton.style.backgroundImage = "url(https://patchwiki.biligame.com/images/lysk/7/7f/8cfam9dgpmzkz2om9j2bjyyqeu9q9sf.png)";
});
panelButton.addEventListener("mouseleave", () => {
panelButton.style.backgroundImage = "url(https://patchwiki.biligame.com/images/lysk/7/7f/8cfam9dgpmzkz2om9j2bjyyqeu9q9sf.png)";
});
}
});
lf.on("node:mouseleave", ({ data, e }) => {
if (!this.allowHover) return;
if (data.type == 'group_node' || data.type == 'extended_read_node') return;
// setTimeout(() => {
let mouseX = e.offsetX;
let mouseY = e.offsetY;
let panelDiv = document.querySelector("#node-page-panel");
if (panelDiv) {
// 查看鼠标是否在#node-page-panel节点上
if (mouseX >= panelDiv.offsetLeft && mouseX <= panelDiv.offsetLeft + panelDiv.offsetWidth &&
mouseY >= panelDiv.offsetTop && mouseY <= panelDiv.offsetTop + panelDiv.offsetHeight) {
return;
}
else {
this.container.removeChild(panelDiv);
}
}
// }, 50);
});
}
// 开启hover面板
openHoverPanel() {
this.allowHover = true;
}
// 关闭hover面板
closeHoverPanel() {
this.allowHover = false;
}
}
// TODO 虚线样式
// class SequenceModel extends PolylineEdgeModel {
// // 设置边样式
// getEdgeStyle() {
// const style = super.getEdgeStyle();
// const { properties } = this;
// if (properties.isstrokeDashed) {
// style.strokeDasharray = '4, 4';
// }
// return style;
// }
// }
// export default {
// type: 'sequence',
// view: PolylineEdge,
// model: SequenceModel,
// };
// TODO 修改节点文本颜色
// graphModel.getNodeModelById(currentNodeId).setProperties({ textColor: '#fff' });
const lf = new LogicFlow({
container: document.querySelector("#container"),
// grid: true,
// edgeType: 'bezier',
allowResize: true,
disabledTools: ['multipleSelect'],
// multipleSelectKey:"shift",
keyboard: {
enabled: true,
},
background: {
backgroundImage: "url(https://patchwiki.biligame.com/images/lysk/4/40/0ibuxl73pgr095hvneel8bf1kwxp6r7.jpg)",
backgroundRepeat: "repeat",
},
idGenerator: (type) => { //重写全局id
let edgeTypes = ['line', 'polyline', 'bezier'];
// 重写node节点id
if (!edgeTypes.includes(type)) {
let id_num = graphModel.nodes.length + 1;
for (let i = 0; i < graphModel.nodes.length; i++) {
if (id_num == graphModel.nodes[i].id.split('_')[1]) {
id_num++;
i--;
}
}
return 'node_' + id_num;
}
},
plugins: [DndPanel, Menu, Control, DynamicGroup, SelectionSelect, HoverNode], //MiniMap
pluginsOptions: {
miniMap: {
isShowCloseIcon: true,
},
},
});
//注册自定义节点 lf.batchRegister([MainLineBox, WorldDeepBox, DatePlotBox, ActivityPlotBox, PhoneInfoBox, GroupBox, MainTitleBox, SubTitleBox, ExtendedReadBox]);//
lf.extension.dndPanel.setPatternItems([
{
type: 'main_line_node',
text: '主线节点',
label: '主线节点',
properties: {},
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAP1JREFUaEPtmUEOgjAQRWfibfQS3oMmamLwGOIxMC5ctPfAQ+hxGANBorhg8RPaJp8tzPTPe10xKpk/mnl+4QCxDdJAMgacO27NVjtV28cONXP+RaRtvL813XfjFXKurETknHj4Pp6Z3kOoD9MBbHi5CaF+pThIUZzWqvbssnl/7eF/G+gH+LxIcYAuk3PlT04OsLQpGlia+PQ8GqABkACvEAgQLqcBGCHYgAZAgHA5DcAIwQY0AAKEy2kARgg2oAEQIFxOAzBCsAENgADhchqAEYINaAAECJfPGjDTbH+v577gyGbFVIm0j78VE3w5IzXgmjUS+PFYGqABkMAbG/IqQCYDb4cAAAAASUVORK5CYII='
},
{
type: 'world_deep_node',
text: '世界深处',
label: '世界深处',
properties: {},
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAQZJREFUaEPtmU0OgjAQhadlixfRS7jy5w5G5CTiSdDEOyg7PIRcBLZSUxMwYqKLl9A2eS6Rmb75vq4YJYH/VOD5hQO4NkgD3hiIV/lcmSgRMTvXoX6db0x7EC1lc01L+15/heJFniml9z6Hf2dTx7rYph8DTJYnYx8YHc2ay6bycZB4fZ6q9nG32eoiecHvDXQDdH/4OIDNNMzJAcY2RQNjEx+eRwM0ABLgFQIBwuU0ACMEG9AACBAupwEYIdiABkCAcDkNwAjBBjQAAoTLaQBGCDagARAgXE4DMEKwAQ2AAOHyvwaC/bwe/IIjnBWTZKLb29eKCb6cjhpwzeoIfH8sDdAASOAJUZEoQF1l6DYAAAAASUVORK5CYII='
},
{
type: 'date_plot_node',
text: '倾心之约',
label: '倾心之约',
properties: {},
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAQhJREFUaEPtmTEKwkAQRWciYqMX0VZiK8Z7qCcx3sSDGIhlxFYvEhsRsrJCIkbQ4kN2F75lzMz+eW+rjErgPw08v3AA1wZpwBsD5XI6V9NbiZi161C/zjdGdhJV+ehwzu17zRUqF3GqKlufw7+z6X6YFZuPAW5JbOyDvuhkkBVXHwe5J7PxQ8zFZhtmpxf8xkA9QP2HjwPYTO2cHKBrUzTQNfH2eTRAAyABXiEQIFxOAzBCsAENgADhchqAEYINaAAECJfTAIwQbEADIEC4nAZghGADGgABwuU0ACMEG9AACBAu/2sg2M/rwS84QlkxqZG0iqrj14oJvpyOGnDN6gh8cywN0ABI4Am8RCZADpxRJQAAAABJRU5ErkJggg=='
},
{
type: 'activity_plot_node',
text: '活动剧情',
label: '活动剧情',
properties: {},
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAQZJREFUaEPtmUEOgkAMRds5jl5BjEvlEuodYC0uDR7CU6BL0DPocWYUEkjERBc/YQbzWcK0077XFVUZ+aMjr1/YgG+DNBCMgfy2XKiatXOy8V3Ut/utlb0xtkyjS1mf60boUMWZMbILufi2NlU5JbNi+9ZAfotd88K5aTI/P0Js5HhdTZzqva4tjYoGfmegbaD9EGIDdU39OtnA0KZoYGji/ftogAZAAhwhECAcTgMwQjABDYAA4XAagBGCCWgABAiH0wCMEExAAyBAOJwGYIRgAhoAAcLhNAAjBBPQAAgQDv9pYLS/1/9gwTGOFdNrBjMRW32smODh9JSAa1ZP4LtraYAGQAJPbn4mQI7cPW8AAAAASUVORK5CYII='
},
{
type: 'phone_info_node',
text: '手机信息',
label: '手机信息',
properties: {},
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAQhJREFUaEPtmdsJwkAQRWdiK6KiTVhCrMAHsQ5jHRGxg6QELUJRsRV3JUIWjKAfF7K7cP2Mmdk75+xXRiXyn0aeXziAb4M0EIyBYlRO1ehcVBa+Q/0631q7lUSO6+vsWL/nrlAxKHNV3YQc3mWzcsju6fJjgN2wsvWD5CmT1SO9hDjIvl+NTU/Odbbslr7hOwPNAM0fIQ5QZ2rn5ABdm6KBrom3z6MBGgAJ8AqBAOFyGoARgg1oAAQIl9MAjBBsQAMgQLicBmCEYAMaAAHC5TQAIwQb0AAIEC6nARgh2IAGQIBw+V8D0X5ej37BEcuKSa3mJjGnrxUTfDk9NeCa1RN4dywN0ABI4AXYnCZABsa7xAAAAABJRU5ErkJggg=='
},
{
type: 'group_node',
label: '分组',
text: ,
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAhRJREFUWEftlj+L1EAYxp8n6yoRPRDxrlG4YnFhk9nGyu4stRLhuFK/gKUifgBBEAU9bb3af5wIIoiCFtrvzBUWguB19wXuCvOYCcmx7q3ZjYSsxQ4M82Z4553fPO87SYgKLY7jKwBeVlhS5vpZ0j1WCdbr9a4HQfCwyhrvKwnkwa0kbVUC6Ha7x9vt9jkAh4suad8m2ZY0MSbJRQA3AByd6Fz1tNP4G2MuSdoAcKoUwBhzEcATSQGAgGRQ2P4ZgF+fzSdJko0jNot5SQ9ardb9wWCwHcfxCoBnEwGiKNogeXWaU436+Jz73I+07865ztQA3lHSNZKHAPjuc5yN+VzpM4cqL5V82cM455gDvABwspEaMMasSnrsJS8ASL6SdCIDMMacT6v5zr9I/bc1JG9ba7/m8T3AelpPiwWApNckF7wcHwFcqHPzoVifnHMruQJ/AAB4A+CYBzhQKXXC+BOPAyD5VlKYAaSF9iMIgpvW2ud1bD6a83EAkt6RPNIYAIB1Sfs1AOC9v1mzBPiQvcSaSkF65x9JWhq6BU9JLs8B5grMFZiJAp1OZyEMwy+SdmYCMPy6nwM0okC/3z+dJMlPANvOuTONp6DsE9+IAv8/AIAd/8daQvoLwK7vkvZIjrN3Se7lPt5eAxD6z2+pAlEUOZJRHb9iY2JY51y/FMAYczklvSvpbJ0QJL+latyy1m6Wxf0N485wXg1uXQsAAAAASUVORK5CYII=',
},
{
type: 'main_title',
label: '主标题',
text: '主标题',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAP5JREFUWEftljFqw0AQRXcO4DIEgQ/jtOnlPpdIZbR/FlZF7hDcJwdIGV/AnXGVLo1BN1iBJggkiIRkFoMkDKNOMMM83kh/l8zCDy083yhAxwCAt3olAF5jVuO9T0IIOxEpnHOI6enXdACstVIXMHPUagBsROTbGHNg5icFUANqYMyA9/6xLMsVgJ/Zf8Msy1Ii+iCiLwDPswK0w9uhQ/kyWRD1h48F3CDADV/zhZmTtg/AWkR+m/dPY0w6K0BznpxE5MzM22sRP9kK/ltUADWgBtTAXRnYN5n9EnMe5Hn+EEJ4r6rq6JzjsR5r7Z6IiqHrftT1Owbm1hoFWNzAHxywbTDOHITTAAAAAElFTkSuQmCC',
},
{
type: 'sub_title',
label: '副标题',
text: '副标题',
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACA0lEQVR4AeyUP0vDQBjG026Ck4sg7m4ubg7STgVBcPHPIlqkOpTi5J/BtpcuFYUiKoJd7FoUKrh00g6Oboqji/0C/QC2/i4kJUmvmpZEpbTc0+e9uzf3PHlzd2Htj39DA/+rAtls9loIcex1W/Sar1rXXYGNVqu1q0rsMtZrfscybgMdCUEPDA0MKzC4FSgUCiOZTCbFXVEBB+l0ekZ1ogKpAJfZbKPRqIdCoTNEF0E+HA4/Y+SK2NF8N4D4KJfZDSpjoIaJbbgEZNuiKkkZWFAawGnLC6xF7NxsNlfoTyBc0XU9iqGirutxxgpAY3xTsgWlAWuyH0YgZj53Z7JBjJ8bgaZNmWyQ0gCOQ15grOD6o/xvDF2CB2BvEdnByItkC0oD1mQ/nMvlBOaTlL5ufx5jS7LPJ6pKtuC7AWthO2OmSH8evHMabuF2C9wA4ke8fcJUXKf/asYGBWoAsQji+1IJXuXTPMnYjsAMcN4Foo+m2AV7o2zGDgrEAOJr7PasVMIEL66nZKyC7wYo+zRCJ0BD/JA3FzLuBt8NIDTH248jfg9/Uo0dkOBmXYZjGJwkp918N4BwVK6O+AKch0+BPIZluMr8B+Pt5jZQIskoXzvj+6AjHwF509V4TAnmHZ/EYYDdEhdC7PGwp6bKl9+c8Wg3MK/bF3cYsE/8Vjz4Bn6q5BcAAAD//3mzGmkAAAAGSURBVAMA7QHjQec9SZUAAAAASUVORK5CYII=',
},
{
type: 'extended_read_node',
label: '拓展阅读',
text: ,
icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAhRJREFUWEftlj+L1EAYxp8n6yoRPRDxrlG4YnFhk9nGyu4stRLhuFK/gKUifgBBEAU9bb3af5wIIoiCFtrvzBUWguB19wXuCvOYCcmx7q3ZjYSsxQ4M82Z4553fPO87SYgKLY7jKwBeVlhS5vpZ0j1WCdbr9a4HQfCwyhrvKwnkwa0kbVUC6Ha7x9vt9jkAh4suad8m2ZY0MSbJRQA3AByd6Fz1tNP4G2MuSdoAcKoUwBhzEcATSQGAgGRQ2P4ZgF+fzSdJko0jNot5SQ9ardb9wWCwHcfxCoBnEwGiKNogeXWaU436+Jz73I+07865ztQA3lHSNZKHAPjuc5yN+VzpM4cqL5V82cM455gDvABwspEaMMasSnrsJS8ASL6SdCIDMMacT6v5zr9I/bc1JG9ba7/m8T3AelpPiwWApNckF7wcHwFcqHPzoVifnHMruQJ/AAB4A+CYBzhQKXXC+BOPAyD5VlKYAaSF9iMIgpvW2ud1bD6a83EAkt6RPNIYAIB1Sfs1AOC9v1mzBPiQvcSaSkF65x9JWhq6BU9JLs8B5grMFZiJAp1OZyEMwy+SdmYCMPy6nwM0okC/3z+dJMlPANvOuTONp6DsE9+IAv8/AIAd/8daQvoLwK7vkvZIjrN3Se7lPt5eAxD6z2+pAlEUOZJRHb9iY2JY51y/FMAYczklvSvpbJ0QJL+latyy1m6Wxf0N485wXg1uXQsAAAAASUVORK5CYII=',
},
])
lf.extension.menu.setMenuConfig({
nodeMenu: [
{
text: "删除",
callback(node) {
lf.deleteNode(node.id);
},
},
], // 覆盖默认的节点右键菜单
});
lf.extension.control.removeItem('zoom-out');
lf.extension.control.removeItem('zoom-in');
lf.extension.control.removeItem('reset');
lf.extension.control.addItem({ // 小地图导航
key: 'mini-map',
iconClass: "custom-minimap",
title: "",
text: "导航",
onClick: (lf, ev) => {
lf.extension.miniMap.show();
lf.extension.miniMap.updatePosition('right-top');
},
});
lf.extension.control.addItem({ //导入json
iconClass: 'input-json',
title: "",
text: "导入json",
onClick: (lf, ev) => {
$('#input-json')[0].style.display = ;
$('#model-json-input')[0].value = ;
},
});
lf.extension.control.addItem({ //打印json
iconClass: 'log-json',
title: "",
text: "导出json",
onClick: (lf, ev) => {
const modelData = graphModel.modelToGraphData(); //图形->数据
$('#show-json')[0].style.display = ;
$('.json-content')[0].innerText = JSON.stringify(modelData);
},
});
lf.extension.control.addItem({ //保存
iconClass: 'save-json',
title: "",
text: "保存",
onClick: (lf, ev) => {
const request = indexedDB.open('readDatabase');
request.onerror = function (event) {
console.error('Database error: ', event.target.errorCode);
};
request.onsuccess = function (event) {
const db = event.target.result;
const newData = { id: 'readData', data: JSON.stringify(graphModel.modelToGraphData()) };
addData(db, newData);
};
},
});
lf.extension.control.addItem({ // 开启框选
iconClass: "selection-open",
title: "",
text: "开启框选",
onClick: (lf, ev) => {
// 开启框选
graphModel.editConfigModel.updateEditConfig({
stopMoveGraph: true,
})
lf.openSelectionSelect();
showCustomAlert('框选已开启!');
},
});
lf.extension.control.addItem({ // 关闭框选
iconClass: "selection-close",
title: "",
text: "关闭框选",
onClick: (lf, ev) => {
// 开启框选
graphModel.editConfigModel.updateEditConfig({
stopMoveGraph: false,
})
lf.closeSelectionSelect();
showCustomAlert('框选已关闭!');
},
});
lf.extension.control.addItem({ // 开启悬浮框
iconClass: "hoverpanel-open",
title: "",
text: "开启悬浮框",
onClick: (lf, ev) => {
lf.extension.hoverNode.openHoverPanel();
showCustomAlert('节点悬浮框已开启!');
},
});
lf.extension.control.addItem({ // 关闭悬浮框
iconClass: "hoverpanel-close",
title: "",
text: "关闭悬浮框",
onClick: (lf, ev) => {
lf.extension.hoverNode.closeHoverPanel();
showCustomAlert('节点悬浮框已关闭!');
},
});
// 消息提示框
function showCustomAlert(message) {
$('#buttons-tip')[0].innerText = message;
$('#buttons-tip')[0].style.display = ;
setTimeout(() => {
$('#buttons-tip')[0].style.display = 'none';
}, 1000);
}
// 复制json到剪贴板
$('.copy-json')[0].addEventListener('click', (event) => {
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
alert('已复制到剪贴板!');
} catch (err) {
console.error('Failed to copy text: ', err);
}
}
copyToClipboard($('.json-content')[0].innerText);
})
// 关闭json弹窗
$('.close-json')[0].addEventListener('click', (event) => {
$('#show-json')[0].style.display = 'none';
})
// 确认导入
$('.confirm-input')[0].addEventListener('click', (event) => {
graphData = JSON.parse($('#model-json-input')[0].value);
lf.render(graphData);
$('#input-json')[0].style.display = 'none';
console.log('流程数据:', graphData)
})
$('.cancle-input')[0].addEventListener('click', (event) => {
$('#input-json')[0].style.display = 'none';
$('#model-json-input')[0].value = ;
})
// 输入节点属性json
$('#node-recommond-input')[0].addEventListener('input', (event) => {
graphModel.getNodeModelById(currentNodeId).setProperties({ recommond: event.target.value });
})
$('#node-url-input')[0].addEventListener('input', (event) => {
graphModel.getNodeModelById(currentNodeId).setProperties({ pageUrl: event.target.value });
})
// 关闭属性栏
$('.close-panel')[0].addEventListener('click', (event) => {
$('.right-panel')[0].style.display = 'none';
})
let graphData, graphModel; const types = ['main_line_node', 'world_deep_node', 'date_plot_node', 'activity_plot_node', 'phone_info_node']
// 从indexedDB中读取数据
const loadDatafromDB = () => {
const request = indexedDB.open('readDatabase');
request.onerror = function (event) {
console.error('Database error: ', event.target.errorCode);
};
request.onsuccess = function (event) {
const db = request.result;
const transaction = db.transaction(['readDataStore'], 'readonly');
const store = transaction.objectStore('readDataStore');
const result = store.get('readData');
// 加载数据成功
result.onsuccess = function (event) {
const data = result.result;
if (data) {
graphData = JSON.parse(data.data);
} else {
graphData = {};
}
console.log('流程数据:', graphData);
lf.render(graphData); //渲染
graphModel = lf.graphModel;
changeLetterSpacing();
};
result.onerror = function (event) {
console.error('Error retrieving data.', event.target.errorCode);
};
}
request.onupgradeneeded = function (event) {
let db = event.target.result;
if (!db.objectStoreNames.contains("readDataStore")) {
db.createObjectStore("readDataStore", { keyPath: "id" });
}
};
}
loadDatafromDB();
// 向indexedDB中写入数据readData
function addData(db, data) {
const transaction = db.transaction(['readDataStore'], 'readwrite');
const store = transaction.objectStore('readDataStore');
const request = store.put(data);
request.onsuccess = function (event) {
alert('数据缓存成功!');
};
request.onerror = function (event) {
console.error('Error adding data.', event.target.errorCode);
};
}
// 节点点击事件
var currentNodeId = ;
lf.on("node:click", (node) => {
console.log('节点数据:', node.data);
currentNodeId = node.data.id;
// 显示属性栏
if (types.includes(node.data.type)) {
$('.right-panel')[0].style.display = ;
const currentNodeModel = graphModel.getNodeModelById(currentNodeId);
$('#current-node')[0].innerText = `${currentNodeModel.text.value}(${currentNodeModel.id})`;
$('#node-recommond-input')[0].value = currentNodeModel.properties.recommond || ;
$('#node-url-input')[0].value = currentNodeModel.properties.pageUrl || ;
}
});
// 节点添加事件
lf.on("node:dnd-add", ({ data }) => {
// 修改分组节点的文本位置
setTimeout(() => {
if (data.type == 'main_title') {
let text = graphModel.getNodeModelById(data.id).text;
text.x = data.x - data.properties.width / 2 + 20 + text.value.length * 17;
text.y = data.y - data.properties.height / 2 + 20;
}
if (data.type == 'sub_title') {
let text = graphModel.getNodeModelById(data.id).text;
text.x = data.x - data.properties.width / 2 + 12 + text.value.length * 15;
text.y = data.y - data.properties.height / 2 + 17;
}
if (data.type === 'group_node') {
data.properties.width = 300;
data.properties.height = 450;
}
changeLetterSpacing();
}, 100)
})
// 更改文本
lf.on("text:update", ({ data }) => {
if (data.type == 'main_title') {
// 修改文本节点位置并更新文本内容
let oldText = $(`#${data.id}`)[0].getAttribute('data-text');
lf.getNodeModelById(data.id).moveText((data.text.length - oldText.length) * 17, 0)
$(`#${data.id}`)[0].setAttribute('data-text', data.text);
}
if (data.type == 'sub_title') {
// 修改文本节点位置并更新文本内容
let oldText = $(`#${data.id}`)[0].getAttribute('data-text');
lf.getNodeModelById(data.id).moveText((data.text.length - oldText.length) * 15, 0)
$(`#${data.id}`)[0].setAttribute('data-text', data.text);
}
setTimeout(() => {
changeLetterSpacing();
}, 100)
})
// 更改标题节点的字间距
const changeLetterSpacing = () => {
let titleNodes = $('.title-node');
for (let i = 0; i < titleNodes.length; i++) {
titleNodes[i].parentElement.parentElement.nextSibling.childNodes[0].setAttribute('letter-spacing', 10)
}
}
// 节点缩放事件
lf.on("node:resize", (e) => {
// 重写分组节点的文本位置
if (e.data.type == 'main_title') {
let height = e.data.properties.height;
let width = e.data.properties.width;
let text = e.model.text
text.x = e.data.x - width / 2 + 20 + text.value.length * 17;
text.y = e.data.y - height / 2 + 20;
}
if (e.data.type == 'sub_title') {
let height = e.data.properties.height;
let width = e.data.properties.width;
let text = e.model.text
text.x = e.data.x - width / 2 + 12 + text.value.length * 15;
text.y = e.data.y - height / 2 + 17;
}
})
lf.on('node:mouseenter', ({ data, e }) => {
if (types.includes(data.type)) {
$(`#${data.id}`)[0].style.backgroundImage = 'url(https://patchwiki.biligame.com/images/lysk/1/1b/sxyq7pmcdcwe6uazcy7uqk89losay2s.png)';
$(`#${data.id}`)[0].style.backgroundSize = '100% 110%';
}
})
lf.on('node:mouseleave', ({ data, e }) => {
if (types.includes(data.type)) {
$(`#${data.id}`)[0].style.backgroundImage = 'url(https://patchwiki.biligame.com/images/lysk/5/51/241yaplcz3ortw7m1n5o2fn37sotr7o.png)';
$(`#${data.id}`)[0].style.backgroundSize = '100% 90%';
}
})
</script>
<style>
/* .main-line-node,
.world-deep-node,
.date-plot-node,
.activity-plot-node,
.phone-info-node */
.node-div {
width: 100%;
height: 100%;
background-image: url(https://patchwiki.biligame.com/images/lysk/5/51/241yaplcz3ortw7m1n5o2fn37sotr7o.png);
background-size: 100% 90%;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
box-sizing: border-box;
}
.main-title-node::after {
content: attr(data-text);
position: absolute;
line-height: 100%;
left: 20px;
top: 55px;
font-size: 24px;
letter-spacing: 10px;
transform: scaleY(-1);
transform-origin: top;
background: linear-gradient(to bottom, transparent 30%, #aa79525c);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.sub-title-node {
background-image: url(https://patchwiki.biligame.com/images/lysk/c/c1/c2xu5ggcepuj340avoyfrf782dxudm7.png);
background-size: contain;
background-repeat: no-repeat;
width: 100%;
height: 100%;
}
.sub-title-node::after {
content: attr(data-text);
position: absolute;
line-height: 100%;
left: 12px;
top: 50px;
font-size: 20px;
letter-spacing: 10px;
transform: scaleY(-1);
transform-origin: top;
background: linear-gradient(to bottom, transparent 30%, #aa79525c);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
.group-node {
width: 100%;
height: 100%;
border-width: 19px 20px 16px 10px;
border-style: solid;
border-image-source: url(https://patchwiki.biligame.com/images/lysk/0/00/5xlyzapkfe69krklaup1dwxxsod8f67.png);
border-image-slice: 4% 6% 2% 3% fill;
border-image-repeat: round;
cursor: pointer;
box-sizing: border-box;
}
.extended-read-node {
width: 100%;
height: 100%;
background-image: url(https://patchwiki.biligame.com/images/lysk/5/57/cne0haqqiyjdpkww3qg54mxwfq2d3mo.png);
background-size: 100% 100%;
}
#node-page-panel {
position: absolute;
width: 250px;
height: 150px;
padding: 20px 25px;
background-image: url(https://patchwiki.biligame.com/images/lysk/c/cb/cfp9bf0jkzu4ffyxeubrf4csbmbcxq4.png);
background-size: 100% 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
}
#node-page-panel>.node-recommond {
width: 100%;
flex: 1;
color: #aa7952;
font-weight: bold;
letter-spacing: 2px;
}
#node-page-panel>.node-button {
width: 90px;
height: 25px;
border: none;
font-size: 13px;
font-weight: bold;
padding: 0;
background-image: url(https://patchwiki.biligame.com/images/lysk/7/7f/8cfam9dgpmzkz2om9j2bjyyqeu9q9sf.png);
background-size: 100% 113%;
background-position: -2px 0px;
background-repeat: no-repeat;
background-color: transparent;
letter-spacing: 4px;
}
#container {
width: 100%;
height: calc(100vh - 20px);
}
#buttons-tip {
position: absolute;
width: 500px;
background-color: #fdaeae;
border-radius: 5px;
text-align: center;
padding: 10px;
top: 0;
left: calc((100vw - 500px) / 2);
}
.overlay {
position: absolute;
width: 80%;
height: 80%;
font-size: 10px;
overflow: auto;
top: 10%;
left: 10%;
background: #e1dddd;
padding: 20px;
}
.right-panel {
position: absolute;
height: 450px;
width: 200px;
right: 0;
bottom: 0;
background-color: #ddd;
padding: 10px;
}
.lf-dndpanel {
top: 60px;
padding: 5px;
margin: 0;
}
.lf-control {
right: unset !important;
}
.custom-minimap {
background: url(data:image/png;base64,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);
}
.input-json {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAi1JREFUWEftl7+LE0EUx98bUsQfjWAjWJizTCOolQg5rGyuEYP+A1eIlkqKzM6bHSFoICJ4hfFfuOaws/G0EUTt9ErlLCysUkSIxHk6snvEsLOzm+RMk22W3Tfv+z77nbezswhLPnDJ9WEF8NeBVqt1olqt1qy1NSFEDQDWmNmd95n5gxBibzQa7XU6ne9FpoyIGsysfGO11utp7J8p6Ha7x4bD4U0AuMHMVzIE+tbavjHmfR5IAvAyB+CgrrcHlFL3AOCBR6SPiI+J6FNW3AFk3WfmRwBwTmsdBnACUsrzQoh3WWKI+BEAmj6IrByllHOlURjAiRDRSWbOnPuyEDMBJE5cFkK89jlRqVSuttvtr6EGnRkgceIhM9/1FHmitb5z2ABnmPmzrwgi1ojoSx5EKQeklBenxYQQESKe8nT4N2ttPBE7aox5NTm2FAARHWdm17UXQtZOxxHxjet2Ivo5M4BLNMacHY/HuwBwuiiEmyZEdK/a/nROKQfSZCnlJSGEg6gUgPiBiOtE9HZh64ATiqLoGiJuhwD+fDc24jh+7hsXdCCKIkJElTyFe+qDg4huMfOWT5yZN+M4fjbXW5AHkKwFMTPLjKaTRHQ/5NBcDqTiSqmnALCZXiPiFhHdDhV38YUAJEI7ALABANta6+tFii8UoNfrHRkMBi/q9Xqj2Wz++u8ARQuWXgdCTThr4Yn+yd8PrABSB+a1OpTv3ZItHSBEfhjx1a/Z0h34DcmTODBHFVvwAAAAAElFTkSuQmCC);
}
.log-json {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAjpJREFUWEftlr9rFEEUx9/b4xAE/wBt1D6Faa3UWhEbvVJQiD8a/4C7me/MsmCnnRgICjYBIRKxNwgBA3baWGgUYhMEKyEc5zxvjl3Z29u9u73duE2mnJ157/O+78csU8OLG/ZPRwC1KwBAAbDzpnYMAMC+iORCOecuhWH4cZZhrbU/884Yc3/WWf89C/BLRI4R0Z/sZefc+RIAS0S0wcw3AAymgYwBaK2FiLaMMRfnoc87A+CriJwdRce8TUQdAHtF9moDAHCZiB4S0fEEIIb4EkN8yIOoDADgHBFZEbkSO9xNA/g9EfkdBIFX4k0WohIAgAtE9FxETieGmXkCIPkmIrettWtpiIUBlFJXiegFM58YMzgFIFaja62N/gGnL89bhFEUnez3+z6npyYknQHAzCsAVisBKKXAzDq3qIoBDuK2fF0pBdOiLypCIvrmnOuEYbhTuQgLot8nonXn3HoQBF5eP4iS9b7dbne63e73WtpQa/1sGNHNVNVvt1qtW71e77Pfi0fxCICZN+MZcFDbINJavx1OS99+fq0aY1YyhezfgiVmfgrgTvItvkfZKVu6DbXWu8PeP0NEL40x17ORxQpsGGPGirSowxYB8O/F3lDeZQA/swBKqbvW2ic5YLnvTGkAAJ+cc2vW2kdFec3br1OBzcFgcC+Koh+NAAB4DOBBGedxd9STAqXUNWvtq8YAyjpOtWE9CvwXgEWdzLjnh9fE715eGx6S/5HZ6QCH6Xmut+AIoAkF/gI/+G0wykYAmgAAAABJRU5ErkJggg==);
}
.save-json {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAATtJREFUWEftl8uRgzAMQCO1k2O2gKSAXLcbQDat5JYilgKy15y2FmvXDPYQxiAR2DCZMRcwsqRn+SMZdhs/sLH/3QNAURQHADgvgULECxH9aG1EACI6MvOXVnGqHzN/WmuvGlsRoCxLAoCKmU1Q9G3/3f/Xydi/AYCG8p6OCiIJYK1tDVdV1ToyxiTXSkoeBtKBiRCrA3jHcyD+BWAOhApAWkxjU6SJhATgd8VRAGiMMaexPhLEJIA0cq18CuIlAMM1AQB7Irq3WzmMon8OhG2oHaG2X8pHBsgRyBHIEVgjF0jnUMwVsw+iUHBIHiR5yJZPA4ylW8nxsGLKAO8TAUVZLk1/K0+V9aH0Dyk/bkN/K0LEm8rywk7OuY+6rr8fChLf8Lcj55xUAy5yj4jNn58mRnmRtRWUN78d/wJKgfAwcdVvgAAAAABJRU5ErkJggg==);
}
.selection-open {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAnpJREFUWEfNV7+rE0EQngkW+QssRbS0tX/vYW8haCc8bSwiiFgFye7sBn+QwkL0FeJTEGy0U0vBWFjZKogiYmFh9QolNsl9Zs7dcO+Su+RCzryFwN5kd+bb2W9mZ5jWPHjN9mkCwFr7hog2mXlLRPrj3yYAlREA570XnVtrEUD3nXNbQZbu1blzLtVpjBFmtjqfoXOydx8AAG8bjYYaTwFkvaMy/c7KF5WFfanOJEn0kBsR/MG5gnVxYeIBvTMFEe+6LkB5O1Mc+B8AZnJAo0BJuDYAkd2R2XVdQd7OwYmCKh4QkYcA9prN5s12u71XxVuFHqjCAWvtYyLaJqLfAG57728sCiJkyOlEVAWAiGwDUBDpAPCDiG557+/PA1IIoEoeEJFjAL7mjTHzRwDeOfesCEhhHpiHPP+/tfYbER2dtY+Z3yVJ0vHep49Z2Vg6CjI8KNP/gpmvi8iHokVLZ0IRuQhgd94Jw3PcEpGdmd6KwiokDG/GidFoVHiyjLE+M18Skc8rBaDKyngQjO0451q1cECVjqPhyTgazhfeL/MVEblbGwBjTIuZ75UY+MPM50Tk1cpJGDxwEsD7jPLnRHQ2a0xzAxGdqYUDgQffiegIAPHeO2vtTyI6nAPxUkROr5yEqjBkti/e+6f63el0NrSwnWHsjnPuWl6+dCIqI5YxpsPMfsrYv3B8sM87iySSZdaIyGsAp/J7Y98Q5bUVpd1u9/hwOPxERIdCNlQyXs5XXPnOSLsYl+mM0s4mWyuGDio9QGwuijxkjLnAzI+YeXcwGFzt9Xq/CjkQn8lsZ6RdTNwQi9WwTtszXqSA1QqorM6shYRVOLN2AH8BG2CPMA76kPQAAAAASUVORK5CYII=);
}
.selection-close {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAUlJREFUWEftlj1Ow0AQhef5DkGipE1NTzgEOQSipPbOrvER4BCROIPhADQU1KkocgQXO2TR2jjrRIpEJm7WraV938y8+QFN/GFifcoAOxkwxjyLyB2AmVJp1kT0aq197N7vAeq6vmzb9ltEbFEUbxoA3vsFAAPgipkDzJ8HmHkhIo21VtUXxhgBcLvV+w2yF8sAOQM5AzkDZ8zACsATM39OMojSEX/2SagOEEpJRBtm/tq30OJ/UtsFxpgmrvNlClGWJcdtqLeMmHlORKsYfQ/RiYsIO+fs6B44ZRekEN77ZYg8FVftggHEhYjM9omrAoTHw4m3NeQ9gA0RhbqPjKnWhl3NiegFwE3qCVUPDAxnnXN8yJg7JfjPUdr1dHgwFe8iPQRxkrPce39dVdVHrHsjIu8h8nQQDSAeRoNI4ww/5k3VEzwDHJOBH1GDWDAXw4uYAAAAAElFTkSuQmCC);
}
.hoverpanel-open {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAPFJREFUWEftlzEOgkAQRWcIBYl4E1t7OYKewNpWQkWYmRvYWHsCE28gl7CytvcGo1ssQSTGggWiu9UmS/Y/XrKzswgDDxw4H8YFkGXZNIqirUsrQRDsmPluM14MEJG6DLd7i0iVW02YeaGqZ0RMXELYjGdeaXJaAexi1yD1n/QA3sDvGkjTdBLH8bx+gsIwvOZ5fuvlFDDzRlX3dQBEvDDzrBeAoigYEalZQ0z18wDegDfgDfyHAWZeqeqxUQlLEUl6MfCpjfsKQFWl616wcTGRaXzf+gHzEREdAGDtEgAATiKybH0XOA5u3X5cT7O/NPAAJmqjMJ+vpdYAAAAASUVORK5CYII=);
}
.hoverpanel-close {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAYdJREFUWEftV7tOw0AQ3LGUkh6Jno4aIZqkpQfRoIBA4h9QdLfnAv8DAtEDLaIMBeFR09FS05PGAxclkhMO8rIdEcWSC/t8O3O7nr0biIgYYw6jKDoguemfi74AtNI0vYzj+AKqWiXZLBo0FB9AzRN4JLkhIvdDSFRH+GacdVQBPMFaSz+LpIvjWEMRrLU+Qx0CzrnaOCihb40xCsD6sQWBRQb+dwZ8D/m+h8lXVHVVVd96ishFBcaYbQBXInIDYE9VP4dI7sw5d9ztvNPLMENAANy22+16kiQfWRLZlYpIvgQGVyIizUqlUm80Gu+BsWvn3E6uJQgFI/kSRdF+mqa7vU4nIn3guZXgt1QDeCW51h3/AV4IgUDK/asg+HwS6NN12SXIgpf+Ew7ovFwZzrwRzbwVeznNdDOa5lyYy264IDB/GQBwp6pbZRgTVX0mud4xJqr6kDGlf53v8rBmyyRXACx1wIEWvDMGcD5NTSedS/IIvYYiIqddkzppvJHneVMqIif+RP0Fs9tU/h3esY0AAAAASUVORK5CYII=);
}
.lf-dnd-item {
font-size: 10px;
}
.lf-dnd-item>.lf-dnd-shape {
background-size: 90%;
height: 30px;
}
.lf-node-text--auto-wrap-inner {
font-weight: bold;
font-size: 18px;
}
</style>

沪公网安备 31011002002714 号