可视化—gojs 超多超实用经验分享(一)
- 1. 设置分组模板,默认样式,统一最小宽度,展开收起状态监听
- 2. 分组名称显示成员个数: 分组名称+成员个数: name(children)
- 3. 分组成员为空时,不显示 placeholder 占位留白
- 4. 分组第一次展开请求获取成员接口,监听展开收起状态 subGraphExpandedChanged:fn
- 5. 设置节点模板
- 6. 设置节点的 icon,此处以文字为例
- 7. 文案太长截取显示...,鼠标悬浮显示全部
- 8. 设置鼠标移入、移出状态,点击节点高亮相关联节点
- 9. 动态追加节点
- 10. 节点众多需要不同表现样式时,可定义不同的节点模板
- 11. 每个节点前后追加 input/output spot 的两种方式
- 12. 设置连线模板,箭头样式,连线上添加关系文字
- 13. 动态追加连线 addLinkData()
- 14. 点击节点使其相关联节点与连线及文字高亮显示
- 15. 点击画布清空当前高亮状态元素
- 16. 删除连线的方法
- 17. 动态根据需求 展开和收起某一个或全部的分组
- 18. 关闭画布重新渲染时的动画
- 19. 画布无限拖拽功能
- 20. 图禁止复制,禁止删除,开启鼠标滚轮缩放,toolTip 触发 hoverDelay 初始定位
- 21. 消除水印
- 更多分享 详见下一篇博文
可视化的库非常多,如:echarts、highcharts、antv 系列、d3、gojs.....
按照可自定义绘图的程度排序: gojs、d3js > antv > echarts 、highcharts
如果需求简单,不需要自定义图元素,那么 echarts 、highcharts 看中哪个 demo 效果就选用哪个库。
如果有一定程度需要自定义图元素,那么可以看 antv g2/g6 demo 是否能满足需求,可自定义大部分图元素。
如果上面的都不能解决你的需求,那么就是高可定制的,可以考虑 d3js、gojs,还是先去看 demo,看哪个更接近你的需求就采用哪个。
gojs 是一个用于构建交互式可视化图的 js 库,使用可自定义的模板和布局构建复杂节点、链接和组,从而构建出简单到复杂的各类图,如流程图、脑图、组织图、甘特图等。而且提供了许多用于用户交互的高级功能,例如拖放、复制和粘贴、就地文本编辑......
本文是关于如何使用可视化库 gojs 的介绍及使用时的小技巧。gojs 的高可自定义性,非常适合需求复杂的图交互。
绘制基本流程简单介绍,
- 引入库,可以下载,也可以引入 cdn 地址
- html 文件创建画布容器,并设置宽高
- 创建实例,定义布局,样式,交互,属性,事件等
- 绑定节点和连线数据,渲染图表
先绘制出基本的实例,让后续的学习,有个大致的轮廓
<template
>>
<div>
<div id="myDiagramDiv" style="height: 1000px;"></div>
</div>
</template>
<script lang="ts" setup>
import go from "@/assets/js/go";
import { onMounted } from "vue";
let diagram: any = null;
const $ = go.GraphObject.make;
onMounted(() => {
init();
});
function init() {
// 创建diagram实例,
diagram = $(go.Diagram, "myDiagramDiv");
// 分组模板
diagram.groupTemplate = $(go.Group, "Auto", {
/* options 后期主要学习部分 */
});
// 连线模板
diagram.linkTemplate = $(go.Link, {
/* options 后期主要学习部分 */
});
// 节点模板
diagram.nodeTemplate = $(go.Node, "Auto", {
/* options 后期主要学习部分 */
});
// 绘制节点模板 追加新的 自定义的模板类型
diagram.nodeTemplateMap.add();
diagram.layout = $(go.LayeredDigraphLayout, {
direction: 0, // 布局方向,0 水平 90 垂直
layerSpacing: 120, // 节点间隔
isOngoing: false,
});
var nodeDataArray = []; // 节点集合
var linkDataArray = []; // 分组集合
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
}
</script>
1. 设置分组模板,默认样式,统一最小宽度,展开收起状态监听
// 分组模板
diagram.groupTemplate = $(
go.Group,
"Auto",
{
layout: $(go.LayeredDigraphLayout, { direction: 0, columnSpacing: 5 }),
isSubGraphExpanded: false, // 默认展开 true 、折叠false.
subGraphExpandedChanged: function (group) {}, // 功能 小 ## 4
},
$(
go.Shape,
"RoundedRectangle", // 分组形状,圆角矩形
{ parameter1: 5, opacity: 0.7, minSize: new go.Size(120, NaN) }, // 圆角 透明度 统一最小宽度
new go.Binding("fill", "color"), // 绑定填充色,如果是固定颜色,可以直接在上述对象中,填写对应的属性,如 fill:"#ccc"
new go.Binding("stroke", "color") // 绑定描边色,同上
),
$(
go.Panel,
"Vertical",
{ defaultAlignment: go.Spot.Left, margin: 4 },
$(
go.Panel,
"Horizontal",
{ defaultAlignment: go.Spot.Top, margin: 4, padding: new go.Margin(5, 5, 5, 2) },
// 设置收缩按钮,用于展开折叠子图 +/-
$("SubGraphExpanderButton", { padding: new go.Margin(0, 5, 0, 0) }),
$(
go.TextBlock,
{ font: "bold 12px Sans-Serif", stroke: "white" },
new go.Binding("text", "", (node) => node.key + `(${node.children})`) // 分组名称+成员个数: name(children)
)
),
// 分组展开后的 面板占位
$(
go.Placeholder,
{ background: "white" },
new go.Binding("padding", "", function (node) {
// 每组背景色和边距
return node.children ? new go.Margin(10, 10) : new go.Margin(0, 10);
})
)
)
);
2. 分组名称显示成员个数: 分组名称+成员个数: name(children)
$(
go.TextBlock,
{ font: "bold 12px Sans-Serif", stroke: "white" },
new go.Binding("text", "", (node) => node.key + `(${node.children})`) // 分组名称+成员个数: name(children)
);
3. 分组成员为空时,不显示 placeholder 占位留白
// 分组展开后的 面板占位
$(
go.Placeholder,
{ background: "white" },
new go.Binding("padding", "", function (node) {
// 每组背景色和边距
return node.children ? new go.Margin(10, 10) : new go.Margin(0, 10);
})
);
4. 分组第一次展开请求获取成员接口,监听展开收起状态 subGraphExpandedChanged:fn
subGraphExpandedChanged: function (group) {
// 子图展开或收起的状态 group.isSubGraphExpanded
var groupData = group.part.data; // 获取分组 数据
if (!groupData.isRequested) {
// 设置一个标识位,标明该分组数据是否 有请求过接口,
// 未请求过,可以编写请求接口代码,或者添加已知节点代码,
groupData.isRequested = true;
diagram.model.addNodeData({
key: "任意要显示的node节点名称",
group: groupData.key,
color: groupData.color,
icon: groupData.icon,
});
// diagram.model.addLinkData({ from: "", to: "" }) // 新增节点 有连线关系则添加连线对象
diagram.animationManager.stopAnimation(); // 取消动画
}
// 请求过 就直接 展开或收起分组 isOngoing 属性true会自动布局,但是会影响用户拖拽效果,因此分组自行布局后,需要在改为false
diagram.layout.isOngoing = true;
setTimeout(() => {
diagram.layout.isOngoing = false;
});
}
5. 设置节点模板
// 节点模板
diagram.nodeTemplate = $(
go.Node,
"Auto",
{
mouseEnter: mouseEnter,
mouseLeave: mouseLeave,
click: nodeclick,
},
$(
go.Shape,
"Rectangle",
{ strokeWidth: 1, stroke: "white", fill: "white" },
new go.Binding("stroke", "isHighlighted", (sel) => (sel ? "#1E90FF" : "white")).ofObject(), // 鼠标选中高亮样式
new go.Binding("strokeWidth", "isHighlighted", (sel) => (sel ? 3 : 1)).ofObject()
),
$(
go.Panel,
"Horizontal",
{ width: 280, padding: new go.Margin(5, 5, 5, 2) },
$(
go.TextBlock, // 设置 icon
{ font: "bold 12px Sans-Serif", stroke: "white", width: 24, textAlign: "center" },
new go.Binding("text", "icon"), // 绑定icon 图表文案
new go.Binding("background", "color") // 绑定 背景色
),
$(
go.TextBlock,
{
margin: 5,
width: 240,
font: "15px Verdana",
stroke: "#444",
maxSize: new go.Size(260, NaN),
maxLines: 1,
overflow: go.TextBlock.OverflowEllipsis, // maxSize maxLines overflow 属性联合使用,用于文案截断 显示...
name: "TEXT", // 命名随意,用于后期 鼠标状态事件,节点成员的获取
},
new go.Binding("text", "key")
),
{
toolTip: $(
// 鼠标悬浮显示全部文案 ,默认触发时间比较长,可以通过属性来修改
"ToolTip",
$(go.TextBlock, { margin: 4 }, new go.Binding("text", "key"))
),
}
)
);
6. 设置节点的 icon,此处以文字为例
$(
go.TextBlock, // 设置 icon
{ font: "bold 12px Sans-Serif", stroke: "white", width: 24, textAlign: "center" },
new go.Binding("text", "icon"), // 绑定icon 图表文案
new go.Binding("background", "color") // 绑定 背景色
),
7. 文案太长截取显示...,鼠标悬浮显示全部
{
toolTip: $(
// 鼠标悬浮显示全部文案 ,默认触发时间比较长,可以通过属性来修改
"ToolTip",
$(go.TextBlock, { margin: 4 }, new go.Binding("text", "key"))
);
}
8. 设置鼠标移入、移出状态,点击节点高亮相关联节点
function mouseEnter(e, obj) {
var text = obj.findObject("TEXT");
text.stroke = "#1E90FF";
}
function mouseLeave(e, obj) {
var text = obj.findObject("TEXT");
text.stroke = "#444";
}
function nodeclick(e, node) {
var diagram = node.diagram;
diagram.clearHighlighteds();
node.findNodesConnected().each(function (l) {
l.isHighlighted = true;
});
node.linksConnected.each(function (n) {
n.isHighlighted = true;
});
}
9. 动态追加节点
diagram.model.addNodeData({
key: "任意要显示的node节点名称",
group: "分组名",
color: "节点背景颜色",
icon: "icon文字",
});
10. 节点众多需要不同表现样式时,可定义不同的节点模板
- 仅有一种不同形式时,可使用
diagram.nodeTemplateMap.add(node)
调用不同的节点模板 - 多种不同模板时,是封装一个方法,生成模板,在调用
diagram.nodeTemplateMap.set(typename, node)
11. 每个节点前后追加 input/output spot 的两种方式
方法一: 该方法需要重点关注的方法是 makePort
,函数调用位置及返回值
var nodeDataArray = [{ key: "A", category: "Start", text: "节点设置左右连接点" }];
var linkDataArray = [
{ from: "A", to: "B", frompid: "1", topid: "1" }, // createPort方法 portId
{ from: "B", to: "C", frompid: "2", topid: "2" },
];
diagram.model.linkFromPortIdProperty = "frompid"; // 连接点对应名称
diagram.model.linkToPortIdProperty = "topid";
diagram.nodeTemplateMap.add(
"Start", // nodeDataArray 中的 category
$(
go.Node,
"Auto",
{ width: 260, height: 80 },
$(go.Shape, "Rectangle", { fill: "white", stroke: "white", strokeWidth: 1 }),
$(
go.Panel,
"Vertical",
{ padding: new go.Margin(5, 5, 5, 2) },
$(
go.TextBlock,
"节点设置左右连接点", // 1. 节点文本也可以直接写在这
{ font: "18px Sans-Serif", stroke: "#444", textAlign: "center" },
new go.Binding("text") // 2.文本也可以通过绑定 nodeDataArray 中的 text, 或者其他任意字段
)
),
$(
go.Panel,
"Vertical",
{
alignment: go.Spot.Left,
alignmentFocus: new go.Spot(0, 0.5, 8, 0),
},
makePort(2, 3).inSpotList // 需要返回一个数组,表示 2个 入边连接点
),
$(
go.Panel,
"Vertical",
{
alignment: go.Spot.Right,
alignmentFocus: new go.Spot(1, 0.5, -8, 0),
},
makePort(2, 3).outSpotList // 需要返回一个数组,表示 3个 出边连接点
)
)
);
function makePort(inCount, outCount) {
let inSpot = inCount;
let outSpot = outCount;
let inSpotList: any = [];
let outSpotList: any = [];
for (let i = 1; i <= inSpot; i++) {
inSpotList.push(createPort(i, "Left"));
}
for (let i = 1; i <= outSpot; i++) {
outSpotList.push(createPort(i, "Right"));
}
function createPort(portId, pos) {
var port = $(go.Shape, "Rectangle", {
fill: "gray",
stroke: null,
desiredSize: new go.Size(8, 8),
portId: String(portId), // 该属性比较重要,用于给每一个连接点 命名,
toMaxLinks: 3,
cursor: "pointer",
});
var panel = $(go.Panel, "Horizontal", { margin: new go.Margin(2, 0) });
port.fromSpot = go.Spot[pos];
port.fromLinkable = true;
panel.alignment = go.Spot["Top" + pos];
panel.add(port);
return panel;
}
return { inSpotList, outSpotList };
}
方法二: 该方法需要重点关注的方法itemArray
,在数据中分别定义了 leftArray
和rightArray
,用于循环显示子元素
diagram.nodeTemplate = $(
go.Node,
"Table",
$(
go.Panel,
"Horizontal",
{ row: 1, column: 2 },
$(
go.TextBlock, // 资产名称
{
margin: 5,
width: 240,
font: "15px Verdana",
stroke: "#444",
}
)
),
$(go.Panel, "Vertical", new go.Binding("itemArray", "leftArray"), {
// 节点 左侧 入边连接点 循环显示
row: 1,
column: 0,
itemTemplate: $(
go.Panel,
{
_side: "left",
fromSpot: go.Spot.Left,
toSpot: go.Spot.Left,
cursor: "pointer",
},
new go.Binding("portId", "portId"),
$(
go.Shape,
"Rectangle",
{
stroke: null,
strokeWidth: 1,
desiredSize: new go.Size(8, 8),
margin: new go.Margin(1, 5, 1, 0),
},
new go.Binding("fill", "portColor")
)
),
}),
$(go.Panel, "Vertical", new go.Binding("itemArray", "rightArray"), {
// 节点 右侧 出边连接点 循环显示
row: 1,
column: 3,
itemTemplate: $(
go.Panel,
{
_side: "right",
fromSpot: go.Spot.Right,
toSpot: go.Spot.Right,
cursor: "pointer",
},
new go.Binding("portId", "portId"),
$(
go.Shape,
"Rectangle",
{
stroke: null,
strokeWidth: 0,
desiredSize: new go.Size(8, 8),
margin: new go.Margin(1, 0),
},
new go.Binding("fill", "portColor")
)
),
})
);
var nodeDataArray = [
{ key: "A", rightArray: [{ portColor: "#33B12C", portId: "left0" }], rightArray: [{ portColor: "#33B12C", portId: "right0" }] },
{ key: "B", rightArray: [{ portColor: "#F29941", portId: "left0" }], rightArray: [{ portColor: "#F29941", portId: "right0" }] },
{ key: "C", rightArray: [{ portColor: "#11C67B", portId: "left0" }], rightArray: [{ portColor: "#11C67B", portId: "right0" }] },
];
var linkDataArray = [
{ from: "A", to: "B", frompid: "right0", topid: "left0" },
{ from: "B", to: "C", frompid: "right0", topid: "left0" },
];
diagram.model.linkFromPortIdProperty = "frompid"; // 连接点对应名称
diagram.model.linkToPortIdProperty = "topid";
12. 设置连线模板,箭头样式,连线上添加关系文字
// 连线模板
diagram.linkTemplate = $(
go.Link,
{
routing: go.Link.Orthogonal,
corner: 25,
relinkableFrom: true,
relinkableTo: true,
},
$(go.Shape, { isPanelMain: true, stroke: "transparent" }),
$(go.Shape, { isPanelMain: true, stroke: "#ccc", strokeWidth: 2 }, new go.Binding("stroke", "color"), new go.Binding("strokeWidth", "strokeWidth")),
$(
go.Shape,
{ toArrow: "standard", strokeWidth: 1, fill: "#ccc" }, // 箭头
new go.Binding("stroke", "color"),
new go.Binding("fill", "color")
),
$(
go.Panel,
"Auto", // 连线上的文字
$(go.Shape, { fill: "white", stroke: "white" }),
$(go.TextBlock, { stroke: "#ff6600", visible: false }, new go.Binding("text", "linkText"), new go.Binding("visible", "linkText", (a) => (a ? true : false)), new go.Binding("stroke", "isHighlighted", (sel) => (sel ? "#1E90FF" : "#ff6600")).ofObject())
)
);
13. 动态追加连线 addLinkData()
diagram.model.addLinkData({ from: "节点key", to: "节点key", color: "线的颜色", linkText: "连线上的文字" }); // 不指定连接点,直接连
diagram.model.addLinkData({ from: "节点key", to: "节点key", color: "线的颜色", linkText: "连线上的文字", frompid: "right0", topid: "left0" }); // 设置入边和出边的连接点
var nodeDataArray = [
{ key: "A", rightArray: [{ portColor: "#33B12C", portId: "left0" }], rightArray: [{ portColor: "#33B12C", portId: "right0" }] },
{ key: "B", rightArray: [{ portColor: "#F29941", portId: "left0" }], rightArray: [{ portColor: "#F29941", portId: "right0" }] },
{ key: "C", rightArray: [{ portColor: "#11C67B", portId: "left0" }], rightArray: [{ portColor: "#11C67B", portId: "right0" }] },
];
var linkDataArray = [
{ from: "A", to: "B", frompid: "right0", topid: "left0" },
{ from: "B", to: "C", frompid: "right0", topid: "left0" },
];
diagram.model.linkFromPortIdProperty = "frompid"; // 连接点对应名称
diagram.model.linkToPortIdProperty = "topid";
14. 点击节点使其相关联节点与连线及文字高亮显示
function nodeclick(e, node) {
var diagram = node.diagram;
diagram.clearHighlighteds();
node.findNodesConnected().each(function (l) {
l.isHighlighted = true;
});
node.linksConnected.each(function (n) {
n.isHighlighted = true;
});
}
15. 点击画布清空当前高亮状态元素
diagram.click = function (e) {
e.diagram.commit(function (d) {
d.clearHighlighteds();
}, "no highlighteds");
};
16. 删除连线的方法
删除一条: diagram.model.removeLinkData(linkData);
,这个方法,我试了几个都没有成功,可能是linkData
获取的不对,又由于我是要全部删除,因此使用了 diagram.model.removeLinkDataCollection
方法,进行批量删除,但是在实际过程中发现,调用这个方法只能删除一半,(也不知道是什么原因,如果有耐心的有缘人,读到此处并解决了问题,欢迎留言帮我解惑),但是呢办法总比困难多,写一个 while 循环就可以搞定了
while (diagram.model.linkDataArray.length) {
diagram.model.removeLinkDataCollection(diagram.model.linkDataArray);
}
17. 动态根据需求 展开和收起某一个或全部的分组
展开或收起某一个分组:
// groupKey 在 nodeDataArray节点列表中的, 分组节点的 Key值
diagram.findNodeForKey(groupKey).isSubGraphExpanded = true; // 展开
diagram.findNodeForKey(groupKey).isSubGraphExpanded = false; // 收起
展开或收起全部分组: 这个功能我用在了,在每次展开某种特定条件的分组时,先关闭之前所有的分组,在进行新一轮的展开操作
function graphExpandCollaps() {
const { nodeDataArray } = diagram.model;
nodeDataArray.forEach((v) => {
if (v.isGroup) {
diagram.findNodeForKey(v.groupName).isSubGraphExpanded = false; // 分组全部收起
}
});
}
18. 关闭画布重新渲染时的动画
diagram.animationManager.stopAnimation(); // 取消动画
19. 画布无限拖拽功能
画布固定宽度和高度之后,对拖拽功能很不友好,当内容比较多时,容易拖拽不动,再则在使用 mac 浏览器时,会触发浏览器的前进后退事件。设置画布可以无限滚动后,解决
diagram.scrollMode = go.Diagram.InfiniteScroll;
20. 图禁止复制,禁止删除,开启鼠标滚轮缩放,toolTip 触发 hoverDelay 初始定位
diagram = $(go.Diagram, "myDiagramDiv", {
"toolManager.hoverDelay": 200, // toolTip触发
"toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom, // 开启鼠标滚轮缩放
// initialContentAlignment: go.Spot.Center, // 居中:第一次 不好使
// contentAlignment: go.Spot.Center, // 可以居中,但是居中之后不可以拖动
initialPosition: new go.Point(-150, -300), // 初始坐标
allowCopy: false, // 禁止复制
allowDelete: false, // 禁止删除
scale: 1, // 缩放会恢复默认值 diagram.scale = 1
minScale: 0.4, // 缩小 diagram.scale -= 0.1
maxScale: 1.4, // 放大 diagram.scale += 0.1
});
21. 消除水印
在其他文章中看到要删除一个函数的方法,但是由于 gojs 是压缩过的,每个版本的变量都不一样,因此查到另外一个方式,亲测有效,
全文搜索 String.fromCharCode(a.charCodeAt(g)^b[(b[c]+b[d])%256])
,大家再搜索时,需要注意一个空格,不然可能会导致搜索不到结果。
在 for 循环的后面 加上一个 判断, 需要跟画布上水印的文字进行比对一下,我觉得其实写一个条件语句,应该就可以命中了。
if (f.indexOf("GoJS 2.2 evaluation") > -1 || f.indexOf("(c) 1998-2022 Northwoods Software") > -1 || f.indexOf("Not for distribution or production use") > -1 || f.indexOf("gojs.net") > -1) {
return "";
} else {
return f;
}
更多分享 详见下一篇博文
可视化—gojs 超多超实用经验分享(一)的更多相关文章
- APICloud超实用经验分享——平台功能
从2016年开始使用APICloud进行app项目开发,到现在也有五六年了.在此过程中伴随着APICloud一起成长,踩过一些坑,自己的技术也提升不少.在APICloud 推出avm框架一年之后,ID ...
- 好文推荐:转载一篇别人kaggle的经验分享
转载:https://www.toutiao.com/i6435866304363627010/ 笔者参加了由Quora举办的Quora Question Pairs比赛,并且获得了前1%的成绩.这是 ...
- 【超酷超实用】CSS3可滑动跳转的分页插件制作教程
原文:[超酷超实用]CSS3可滑动跳转的分页插件制作教程 今天我要向大家分享一款很特别的CSS3分页插件,这款分页插件不仅可以点击分页按钮来实现分页,而且可以滑动滑杆来实现任意页面的跳转,看看都非常酷 ...
- 第9期Unity User Group Beijing图文报道:《Unity实战经验分享》
时间来到了金秋九月,北京UUG活动也来到了第九期.本次活动的主题为<Unity实战经验分享>,为此我们邀请了3位资深的行业大神.这次我们仍然在北京市海淀区丹棱街5号微软大厦举行活动,在这里 ...
- 使用latex撰写博士,硕士学位论文(浙大博士经验分享)
使用latex撰写博士,硕士学位论文(浙大博士经验分享) 浙大博士: 个人感觉,还是要用latex来写.因为之前发过几篇word排版的中文论文,在参考文献的引用.文字格式调整上,实在是难受.如果坚持 ...
- Kaggle比赛冠军经验分享:如何用 RNN 预测维基百科网络流量
Kaggle比赛冠军经验分享:如何用 RNN 预测维基百科网络流量 from:https://www.leiphone.com/news/201712/zbX22Ye5wD6CiwCJ.html 导语 ...
- 【干货】Kaggle 数据挖掘比赛经验分享(mark 专业的数据建模过程)
简介 Kaggle 于 2010 年创立,专注数据科学,机器学习竞赛的举办,是全球最大的数据科学社区和数据竞赛平台.笔者从 2013 年开始,陆续参加了多场 Kaggle上面举办的比赛,相继获得了 C ...
- Splunk大数据分析经验分享
转自:http://www.freebuf.com/articles/database/123006.html Splunk大数据分析经验分享:从入门到夺门而逃 Porsche 2016-12-19 ...
- Kaggle 数据挖掘比赛经验分享(转)
原作者:陈成龙 简介 Kaggle 于 2010 年创立,专注数据科学,机器学习竞赛的举办,是全球最大的数据科学社区和数据竞赛平台.笔者从 2013 年开始,陆续参加了多场 Kaggle上面举办的比 ...
- Kaggle 数据挖掘比赛经验分享
文章发布于公号[数智物语] (ID:decision_engine),关注公号不错过每一篇干货. 来源 | 腾讯广告算法大赛 作者 | 陈成龙 Kaggle 于 2010 年创立,专注数据科学,机器学 ...
随机推荐
- Unity泛型单例模式
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Singleto ...
- 记录下老dropbox的使用
32-bit: wget -O - "https://www.dropbox.com/download?plat=lnx.x86" | tar xzf - 64-bit: wget ...
- Vue中 ref、$refs区别与使用
定义2个组件: 子组件ChildrenSubRef.vue: 1 <template> 2 <div> 3 4 </div> 5 </template> ...
- mysql error Code 1441:datetime function: datetime field overflow
mysql error Code 1441:datetime function: datetime field overflow 网上找了好久,也没有解决 最后发现有个left join 表,on关 ...
- python中的反射机制
转自https://www.cnblogs.com/renjie1105/p/15909285.html python反射简介 在做程序开发中,我们常常会遇到这样的需求:需要执行对象里的某个方法,或需 ...
- 03-Spring使用注解方式注入
基于注解的DI注入 1.导包 环境搭建:导入aop包(spring-aop-4.1.6.RELEASE.jar) 2.创建类 3. 创建spring.xml配置文件(必须在src目录下) 该配置文件与 ...
- 服务器链接工具MobaXterm
链接:https://pan.baidu.com/s/15zC4JC0XOKYI1lN5bkB3fw 提取码:9zc8 每次使用都需要输入密码.修改密码: 链接:https://pan.baidu.c ...
- ArchKeeper (开篇):架构守护平台的问题与理念
作者:京东科技 倪新明 在敏捷开发环境下,系统通过迭代增量的交付价值,系统架构也是如此.团队不可能在项目之初就建立完美的系统架构,系统架构应该随着系统迭代不断演进.架构演进和架构腐化是看待架构的不同视 ...
- 如何搭建属于自己的服务器(Linux7.6版)
从0搭建属于自己的服务器 最近小伙伴推荐的华为云活动,购买服务器相当的划算,本人也是耗费巨资购买了一台2核4G HECS云服务器. 话不多说,在这里给华为云打一个广子,活动力度还是很不错的. 活动详情 ...
- Android笔记--监听短信内容
监听短信内容 就比如说是在我们用一个软件需要使用"获取验证码"的功能时,能够跟短信的验证码互通,实现较为完整的登录功能: 监听短信内容主要是利用了contentObserver实现 ...