本章分享一下如何使用 Konva 绘制基础图形:矩形、直线、折线,希望大家继续关注和支持哈!

请大家动动小手,给我一个免费的 Star 吧~

大家如果发现了 Bug,欢迎来提 Issue 哟~

github源码

gitee源码

示例地址

矩形

先上效果!



实现方式基本和《前端使用 Konva 实现可视化设计器(21)- 绘制图形(椭圆)》是一致的,主要区别矩形的大小和椭圆形的大小设置方式不一样,特别是矩形无需设置 offset。其它就不再赘述了哈。

直线、折线

先上效果!



简单描述一下上面的交互:

首先,绘制一条直线,淡出画一条直线还是比较简单的,根据记录鼠标按下的位置和鼠标释放的位置,就很容易得到 Konva.Line 的 points 应该设定的值了。

然后,沿用绘制 椭圆形、矩形 的思路,它只有特定的 2 个“调整点”,分别代表 起点 和 终点。

// src/Render/graphs/Line.ts

// 略

/**
* 直线、折线
*/
export class Line extends BaseGraph {
// 略 constructor(render: Types.Render, dropPoint: Konva.Vector2d) {
super(render, dropPoint, {
type: Types.GraphType.Line,
// 定义了 2 个 调整点
anchors: [{ adjustType: 'start' }, { adjustType: 'end' }].map((o) => ({
adjustType: o.adjustType // 调整点 类型定义
})),
linkAnchors: [
{ x: 0, y: 0, alias: 'start' },
{ x: 0, y: 0, alias: 'end' }
] as Types.AssetInfoPoint[]
}) // 新建 直线、折线
this.line = new Konva.Line({
name: 'graph',
x: 0,
y: 0,
stroke: 'black',
strokeWidth: 1,
hitStrokeWidth: render.toStageValue(5)
}) // 给予 1 像素,防止导出图片 toDataURL 失败
this.group.size({
width: 1,
height: 1
}) // 加入
this.group.add(this.line)
// 鼠标按下位置 作为起点
this.group.position(this.dropPoint)
} // 实现:拖动进行时
override drawMove(point: Konva.Vector2d): void {
// 鼠标拖动偏移量
const offsetX = point.x - this.dropPoint.x,
offsetY = point.y - this.dropPoint.y // 起点、终点
const linkPoints = [
[this.line.x(), this.line.y()],
[this.line.x() + offsetX, this.line.y() + offsetY]
] // 直线、折线 路径
this.line.points(_.flatten(linkPoints)) // 更新 图形 的 调整点 的 锚点位置
Line.updateAnchorShadows(this.group, this.anchorShadows, this.line) // 更新 图形 的 连接点 的 锚点位置
Line.updateLinkAnchorShadows(this.group, this.linkAnchorShadows, this.line) // 重绘
this.render.redraw([Draws.GraphDraw.name, Draws.LinkDraw.name, Draws.PreviewDraw.name])
} // 实现:拖动结束
override drawEnd(): void {
if (this.line.width() <= 1 && this.line.height() <= 1) {
// 加入只点击,无拖动 // 默认大小
const width = Line.size,
height = width // 起点、终点
const linkPoints = [
[this.line.x(), this.line.y()],
[this.line.x() + width, this.line.y() + height]
] // 直线、折线 位置大小
this.line.points(_.flatten(linkPoints))
} // 更新 调整点(拐点)
Line.updateAnchor(this.render, this.group) // 更新 图形 的 调整点 的 锚点位置
Line.updateAnchorShadows(this.group, this.anchorShadows, this.line) // 更新 图形 的 连接点 的 锚点位置
Line.updateLinkAnchorShadows(this.group, this.linkAnchorShadows, this.line) // 对齐线清除
this.render.attractTool.alignLinesClear() // 更新历史
this.render.updateHistory() // 重绘
this.render.redraw([Draws.GraphDraw.name, Draws.LinkDraw.name, Draws.PreviewDraw.name])
} // 略
}

调整点,可以改变 直线、折线 的 起点、终点。

// 略

/**
* 直线、折线
*/
export class Line extends BaseGraph {
// 实现:更新 图形 的 调整点 的 锚点位置
static override updateAnchorShadows(
graph: Konva.Group,
anchorShadows: Konva.Circle[],
shape?: Konva.Line
): void {
if (shape) {
const points = shape.points()
//
for (const shadow of anchorShadows) {
switch (shadow.attrs.adjustType) {
case 'start':
shadow.position({
x: points[0],
y: points[1]
})
break
case 'end':
shadow.position({
x: points[points.length - 2],
y: points[points.length - 1]
})
break
}
}
}
} // 略 // 实现:生成 调整点
static override createAnchorShapes(
render: Types.Render,
graph: Konva.Group,
anchorAndShadows: {
anchor: Types.GraphAnchor
anchorShadow: Konva.Circle
shape?: Konva.Shape
}[],
adjustAnchor?: Types.GraphAnchor
): {
anchorAndShadows: {
anchor: Types.GraphAnchor
anchorShadow: Konva.Circle
shape?: Konva.Shape | undefined
}[]
} {
// stage 状态
const stageState = render.getStageState() const graphShape = graph.findOne('.graph') as Konva.Line if (graphShape) {
const points = graphShape.points() for (const anchorAndShadow of anchorAndShadows) {
let rotate = 0
const { anchor, anchorShadow } = anchorAndShadow const x = render.toStageValue(anchorShadow.getAbsolutePosition().x - stageState.x),
y = render.toStageValue(anchorShadow.getAbsolutePosition().y - stageState.y) if (anchor.adjustType === 'manual') {
// 略
} else {
if (anchor.adjustType === 'start') {
rotate = Line.calculateAngle(points[2] - points[0], points[3] - points[1])
} else if (anchor.adjustType === 'end') {
rotate = Line.calculateAngle(
points[points.length - 2] - points[points.length - 4],
points[points.length - 1] - points[points.length - 3]
)
} const cos = Math.cos((rotate * Math.PI) / 180)
const sin = Math.sin((rotate * Math.PI) / 180) const offset = render.toStageValue(render.pointSize + 5) const offsetX = offset * sin
const offsetY = offset * cos const anchorShape = new Konva.Circle({
name: 'anchor',
anchor: anchor,
//
fill:
adjustAnchor?.adjustType === anchor.adjustType && adjustAnchor?.groupId === graph.id()
? 'rgba(0,0,255,0.8)'
: 'rgba(0,0,255,0.2)',
radius: render.toStageValue(3),
strokeWidth: 0,
// 位置
x: x,
y: y,
offsetX:
anchor.adjustType === 'start' ? offsetX : anchor.adjustType === 'end' ? -offsetX : 0,
offsetY:
anchor.adjustType === 'start' ? offsetY : anchor.adjustType === 'end' ? -offsetY : 0,
// 旋转角度
rotation: graph.getAbsoluteRotation()
}) anchorShape.on('mouseenter', () => {
anchorShape.fill('rgba(0,0,255,0.8)')
document.body.style.cursor = 'move'
})
anchorShape.on('mouseleave', () => {
anchorShape.fill(
anchorShape.attrs.adjusting ? 'rgba(0,0,255,0.8)' : 'rgba(0,0,255,0.2)'
)
document.body.style.cursor = anchorShape.attrs.adjusting ? 'move' : 'default'
}) anchorAndShadow.shape = anchorShape
}
}
} return { anchorAndShadows }
} // 略 // 实现:调整 图形
static override adjust(
render: Types.Render,
graph: Konva.Group,
graphSnap: Konva.Group,
adjustShape: Konva.Shape,
anchorAndShadows: {
anchor: Types.GraphAnchor
anchorShadow: Konva.Circle
shape?: Konva.Shape | undefined
}[],
startPoint: Konva.Vector2d,
endPoint: Konva.Vector2d
) {
// 目标 直线、折线
const line = graph.findOne('.graph') as Konva.Line
// 镜像
const lineSnap = graphSnap.findOne('.graph') as Konva.Line // 调整点 锚点
const anchors = (graph.find('.anchor') ?? []) as Konva.Circle[]
// 镜像
const anchorsSnap = (graphSnap.find('.anchor') ?? []) as Konva.Circle[] // 连接点 锚点
const linkAnchors = (graph.find('.link-anchor') ?? []) as Konva.Circle[] if (line && lineSnap) {
// stage 状态
const stageState = render.getStageState() {
const [graphRotation, adjustType, ex, ey] = [
Math.round(graph.rotation()),
adjustShape.attrs.anchor?.adjustType,
endPoint.x,
endPoint.y
] const { x: cx, y: cy, width: cw, height: ch } = graphSnap.getClientRect() const { x, y } = graph.position() const [centerX, centerY] = [cx + cw / 2, cy + ch / 2] const { x: sx, y: sy } = Line.rotatePoint(ex, ey, centerX, centerY, -graphRotation)
const { x: rx, y: ry } = Line.rotatePoint(x, y, centerX, centerY, -graphRotation) const points = line.points()
const manualPoints = (line.attrs.manualPoints ?? []) as Types.LineManualPoint[] if (adjustType === 'manual') {
// 略
} else {
const anchor = anchors.find((o) => o.attrs.adjustType === adjustType)
const anchorShadow = anchorsSnap.find((o) => o.attrs.adjustType === adjustType) if (anchor && anchorShadow) {
{
const linkPoints = [
[points[0], points[1]],
...manualPoints.sort((a, b) => a.index - b.index).map((o) => [o.x, o.y]),
[points[points.length - 2], points[points.length - 1]]
] switch (adjustType) {
case 'start':
{
linkPoints[0] = [sx - rx, sy - ry]
line.points(_.flatten(linkPoints))
}
break
case 'end':
{
linkPoints[linkPoints.length - 1] = [sx - rx, sy - ry]
line.points(_.flatten(linkPoints))
}
break
}
}
}
}
} // 更新 调整点(拐点)
Line.updateAnchor(render, graph) // 更新 调整点 的 锚点 位置
Line.updateAnchorShadows(graph, anchors, line) // 更新 图形 的 连接点 的 锚点位置
Line.updateLinkAnchorShadows(graph, linkAnchors, line) // 更新 调整点 位置
for (const anchor of anchors) {
for (const { shape } of anchorAndShadows) {
if (shape) {
if (shape.attrs.anchor?.adjustType === anchor.attrs.adjustType) {
const anchorShadow = graph
.find(`.anchor`)
.find((o) => o.attrs.adjustType === anchor.attrs.adjustType) if (anchorShadow) {
shape.position({
x: render.toStageValue(anchorShadow.getAbsolutePosition().x - stageState.x),
y: render.toStageValue(anchorShadow.getAbsolutePosition().y - stageState.y)
})
shape.rotation(graph.getAbsoluteRotation())
}
}
}
}
} // 重绘
render.redraw([Draws.GraphDraw.name, Draws.LinkDraw.name, Draws.PreviewDraw.name])
}
} // 略
}

折线

相比绘制 椭圆形、矩形 比较不一样的地方在于,椭圆形、矩形 的“调整点”是固定的,而绘制 折线 不一样,没调整一个新的拐点,就会新增 2 个新调整点,整体交互与 手动连接线 类似。

// src/Render/draws/GraphDraw.ts

// 略

export interface GraphDrawState {
// 略 /**
* 调整中 调整点
*/
adjustAnchor?: Types.GraphAnchor /**
* 鼠标按下 调整点 位置
*/
startPointCurrent: Konva.Vector2d /**
* 图形 group
*/
graphCurrent?: Konva.Group /**
* 图形 group 镜像,用于计算位置、大小的偏移
*/
graphCurrentSnap?: Konva.Group
} // 略 export class GraphDraw extends Types.BaseDraw implements Types.Draw {
// 略 state: GraphDrawState = {
adjusting: false,
adjustGroupId: '',
startPointCurrent: { x: 0, y: 0 }
} // 略 override draw() {
this.clear()
// 所有图形
const graphs = this.render.layer
.find('.asset')
.filter((o) => o.attrs.assetType === Types.AssetType.Graph) as Konva.Group[] for (const graph of graphs) {
// 非选中状态才显示 调整点
if (!graph.attrs.selected) {
// 略 for (const anchorAndShadow of anchorAndShadows) {
const { shape } = anchorAndShadow if (shape) {
// 鼠标按下
shape.on('mousedown', () => {
const pos = this.getStagePoint()
if (pos) {
this.state.adjusting = true
this.state.adjustAnchor = shape.attrs.anchor
this.state.adjustGroupId = graph.id() this.state.startPointCurrent = pos this.state.graphCurrent = graph
this.state.graphCurrentSnap = graph.clone() shape.setAttr('adjusting', true) if (this.state.adjustAnchor) {
switch (shape.attrs.anchor?.type) {
case Types.GraphType.Line:
// 使用 直线、折线 静态处理方法
Graphs.Line.adjustStart(this.render, graph, this.state.adjustAnchor, pos)
break
}
}
}
}) // 略 // 调整结束
this.render.stage.on('mouseup', () => {
// 略 this.state.adjusting = false
this.state.adjustAnchor = undefined
this.state.adjustGroupId = '' // 恢复显示所有 调整点
for (const { shape } of anchorAndShadows) {
if (shape) {
shape.opacity(1)
shape.setAttr('adjusting', false)
if (shape.attrs.anchor?.type === Types.GraphType.Line) {
if (shape.attrs.anchor.adjusted) {
shape.fill('rgba(0,0,0,0.4)')
} else {
shape.fill('rgba(0,0,255,0.2)')
}
} else {
shape.stroke('rgba(0,0,255,0.2)')
}
} // 略
} // 略
}) // 略
}
}
}
}
}
}

上面除了需要更多的状态记录 调整 信息,还需要定义 Line 特有的 adjustStart 方法:

// src/Render/graphs/Line.ts

// 略

/**
* 直线、折线
*/
export class Line extends BaseGraph {
// 略 /**
* 调整之前
*/
static adjustStart(
render: Types.Render,
graph: Konva.Group,
adjustAnchor: Types.GraphAnchor & { manualIndex?: number; adjusted?: boolean },
endPoint: Konva.Vector2d
) {
const { x: gx, y: gy } = graph.position() const shape = graph.findOne('.graph') as Konva.Line if (shape && typeof adjustAnchor.manualIndex === 'number') {
const manualPoints = (shape.attrs.manualPoints ?? []) as Types.LineManualPoint[]
if (adjustAnchor.adjusted) {
//
} else {
manualPoints.push({
x: endPoint.x - gx,
y: endPoint.y - gy,
index: adjustAnchor.manualIndex
})
shape.setAttr('manualPoints', manualPoints)
} // 更新 调整点(拐点)
Line.updateAnchor(render, graph)
}
}
} // 略

动态的调整点,会记录在 line 的 attrs 中 manualPoints,每次首次调整一处 拐点,就会新增一个 新 拐点,主要应用在:

// 略

/**
* 直线、折线
*/
export class Line extends BaseGraph {
// 略 // 实现:调整 图形
static override adjust(
render: Types.Render,
graph: Konva.Group,
graphSnap: Konva.Group,
adjustShape: Konva.Shape,
anchorAndShadows: {
anchor: Types.GraphAnchor
anchorShadow: Konva.Circle
shape?: Konva.Shape | undefined
}[],
startPoint: Konva.Vector2d,
endPoint: Konva.Vector2d
) {
// 目标 直线、折线
const line = graph.findOne('.graph') as Konva.Line
// 镜像
const lineSnap = graphSnap.findOne('.graph') as Konva.Line // 调整点 锚点
const anchors = (graph.find('.anchor') ?? []) as Konva.Circle[]
// 镜像
const anchorsSnap = (graphSnap.find('.anchor') ?? []) as Konva.Circle[] // 连接点 锚点
const linkAnchors = (graph.find('.link-anchor') ?? []) as Konva.Circle[] if (line && lineSnap) {
// stage 状态
const stageState = render.getStageState() {
const [graphRotation, adjustType, ex, ey] = [
Math.round(graph.rotation()),
adjustShape.attrs.anchor?.adjustType,
endPoint.x,
endPoint.y
] const { x: cx, y: cy, width: cw, height: ch } = graphSnap.getClientRect() const { x, y } = graph.position() const [centerX, centerY] = [cx + cw / 2, cy + ch / 2] const { x: sx, y: sy } = Line.rotatePoint(ex, ey, centerX, centerY, -graphRotation)
const { x: rx, y: ry } = Line.rotatePoint(x, y, centerX, centerY, -graphRotation) const points = line.points()
const manualPoints = (line.attrs.manualPoints ?? []) as Types.LineManualPoint[] if (adjustType === 'manual') {
if (adjustShape.attrs.anchor?.manualIndex !== void 0) {
const index = adjustShape.attrs.anchor?.adjusted
? adjustShape.attrs.anchor?.manualIndex
: adjustShape.attrs.anchor?.manualIndex + 1 const manualPointIndex = manualPoints.findIndex((o) => o.index === index) if (manualPointIndex > -1) {
manualPoints[manualPointIndex].x = sx - rx
manualPoints[manualPointIndex].y = sy - ry
} const linkPoints = [
[points[0], points[1]],
...manualPoints.sort((a, b) => a.index - b.index).map((o) => [o.x, o.y]),
[points[points.length - 2], points[points.length - 1]]
] line.setAttr('manualPoints', manualPoints) line.points(_.flatten(linkPoints)) //
const adjustAnchorShadow = anchors.find(
(o) => o.attrs.adjustType === 'manual' && o.attrs.manualIndex === index
)
if (adjustAnchorShadow) {
adjustAnchorShadow.position({
x: sx - rx,
y: sy - ry
})
}
}
} else {
// 略
}
} // 略
}
} // 略 /**
* 更新 调整点(拐点)
* @param render
* @param graph
*/
static updateAnchor(render: Types.Render, graph: Konva.Group) {
const anchors = graph.attrs.anchors ?? []
const anchorShadows = graph.find('.anchor') ?? [] const shape = graph.findOne('.graph') as Konva.Line if (shape) {
// 已拐
let manualPoints = (shape.attrs.manualPoints ?? []) as Types.LineManualPoint[]
const points = shape.points() // 调整点 + 拐点
const linkPoints = [
[points[0], points[1]],
...manualPoints.sort((a, b) => a.index - b.index).map((o) => [o.x, o.y]),
[points[points.length - 2], points[points.length - 1]]
] // 清空 调整点(拐点),保留 start end
anchors.splice(2)
const shadows = anchorShadows.splice(2)
for (const shadow of shadows) {
shadow.remove()
shadow.destroy()
} manualPoints = [] for (let i = linkPoints.length - 1; i > 0; i--) {
linkPoints.splice(i, 0, [])
} // 调整点(拐点)
for (let i = 1; i < linkPoints.length - 1; i++) {
const anchor = {
type: graph.attrs.graphType,
adjustType: 'manual',
//
name: 'anchor',
groupId: graph.id(),
//
manualIndex: i,
adjusted: false
} if (linkPoints[i].length === 0) {
anchor.adjusted = false // 新增
const prev = linkPoints[i - 1]
const next = linkPoints[i + 1] const circle = new Konva.Circle({
adjustType: anchor.adjustType,
anchorType: anchor.type,
name: anchor.name,
manualIndex: anchor.manualIndex,
radius: 0,
// radius: render.toStageValue(2),
// fill: 'red',
//
x: (prev[0] + next[0]) / 2,
y: (prev[1] + next[1]) / 2,
anchor
}) graph.add(circle)
} else {
anchor.adjusted = true // 已拐
const circle = new Konva.Circle({
adjustType: anchor.adjustType,
anchorType: anchor.type,
name: anchor.name,
manualIndex: anchor.manualIndex,
adjusted: true,
radius: 0,
// radius: render.toStageValue(2),
// fill: 'red',
//
x: linkPoints[i][0],
y: linkPoints[i][1],
anchor
}) graph.add(circle) manualPoints.push({
x: linkPoints[i][0],
y: linkPoints[i][1],
index: anchor.manualIndex
})
} anchors.push(anchor)
} shape.setAttr('manualPoints', manualPoints) graph.setAttr('anchors', anchors)
}
} // 略
}

上面简单的说,就是处理 manualPoints 的算法,负责控制新增拐点,然后把“点”们插入到 起点、终点 之间,最后处理成 Konva.Line 的 points 的值。

顺带一说。区分 起点、终点 和 拐点 是通过 attrs 中的 adjustType 字段;区分 拐点 是否已经操作过 是通过 attrs 中的 adjusted 字段;拐点是存在明确的顺序的,会记录在 attrs 的 manualIndex 字段中。

个人觉得,目前,绘制图形的 代码结构 和 变量命名 容易产生歧义,后面尽量抽出时间重构一下,大家支持支持 !

Thanks watching~

More Stars please!勾勾手指~

源码

gitee源码

示例地址

前端使用 Konva 实现可视化设计器(22)- 绘制图形(矩形、直线、折线)的更多相关文章

  1. 惊闻企业Web应用生成平台 活字格 V4.0 免费了,不单可视化设计器免费,服务器也免费!

    官网消息: 针对活字格开发者,新版本完全免费!您可下载活字格 Web 应用生成平台 V4.0 Updated 1,方便的创建各类 Web 应用系统,任意部署,永不过期. 我之前学习过活字格,也曾经向用 ...

  2. ActiveReports 9 新功能:可视化查询设计器(VQD)介绍

    在最新发布的ActiveReports 9报表控件中添加了多项新功能,以帮助你在更短的时间里创建外观绚丽.功能强大的报表系统,本文将重点介绍可视化数据查询设计器,无需手动编写任何SQL语句,主要内容如 ...

  3. (原创)【B4A】一步一步入门02:可视化界面设计器、控件的使用

    一.前言 上篇 (原创)[B4A]一步一步入门01:简介.开发环境搭建.HelloWorld 中我们创建了默认的项目,现在我们来看一下B4A项目的构成,以及如何所见即所得的设计界面,并添加和使用自带的 ...

  4. Windows Phone 十二、设计器同步

    在设计阶段为页面添加数据源 Blend或者VS的可视化设计器会跑我们的代码,然后来显示出来,当我们Build之后,设计器会进入页面的构造函数,调用InitializeComponent();方法来将U ...

  5. WinForms项目升级.Net Core 3.0之后,没有WinForm设计器?

    目录 .NET Conf 2019 Window Forms 设计器 .NET Conf 2019 2019 9.23-9.25召开了 .NET Conf 2019 大会,大会宣布了 .Net Cor ...

  6. Activiti工作流学习之SpringBoot整合Activiti5.22.0实现在线设计器(二)

    一.概述 网上有很多关于Eclipse.IDEA等IDE插件通过拖拽的方式来画工作流程图,个人觉得还是不够好,所以花点时间研究了一下Activiti在线设计器,并与SpringBoot整合. 二.实现 ...

  7. VS2015 android 设计器不能可视化问题解决。

    近期安装了VS2015,体验了一下android 的开发,按模板创建执行了个,试下效果非常不错.也能够可视化设计.但昨天再次打开或创建一个android程序后,设计界面直接不能显示,显示错误:(可能是 ...

  8. 可视化流程设计——流程设计器演示(基于Silverlight)

    上一篇文章<通用流程设计>对鄙人写的通用流程做了一定的介绍,并奉上了相关源码.但一个好的流程设计必少不了流程设计器的支持,本文将针对<通用流程设计>中的流程的设计器做一个简单的 ...

  9. F2工作流引擎之-纯JS Web在线可拖拽的流程设计器(八)

          Web纯JS流程设计器无需编程,完全是通过鼠标拖.拉.拽的方式来完成,支持串行.并行.分支.异或分支.M取N路分支.会签.聚合.多重聚合.退回.传阅.转交,都可以非常方便快捷地实现,管理员 ...

  10. 纯JS Web在线可拖拽的流程设计器

    F2工作流引擎之-纯JS Web在线可拖拽的流程设计器 Web纯JS流程设计器无需编程,完全是通过鼠标拖.拉.拽的方式来完成,支持串行.并行.分支.异或分支.M取N路分支.会签.聚合.多重聚合.退回. ...

随机推荐

  1. SQLServer 的Distinct

    distinct去除重复的数据(distinct是对整个结果集进行数据重复处理,不是针对某一列) -> 检查返回不重复的数据(对于整条记录不重复才会去除,如ID不一样) 用法:select di ...

  2. 【解决方案】智能UI自动化测试

    你的UI自动化追得上业务的变更和UI更迭吗?当今瞬息万变的时代,成千上万的App围绕着现代人生活的点点滴滴.为了满足用户的好的体验和时刻的新鲜感,这些App需要时刻保持变化,也给 UI自动化落地实施带 ...

  3. 如何更好的使用 Windows

    如何更好的使用 Windows Microsoft 辅助功能和工具 键盘快捷方式,常用 ctrl+C 复制 ctrl+V 粘贴 ctrl+X 剪切 ctrl+Z 撤销 ctrl+Y 回退 alt+ta ...

  4. 手把手教你!STM32单片机入门指南:从初级到中级工程师的学习路线

    ​在当今科技日新月异的时代,嵌入式系统作为智能设备的核心驱动力,正以前所未有的速度渗透到我们生活的方方面面.STM32系列微控制器,以其高性能.低功耗及丰富的外设资源,成了许多开发者踏入嵌入式领域首选 ...

  5. ansible 一键部署openstack (双节点)

    1.三台虚拟机设置 ansible 内存 2GB 处理器 4 硬盘 40GB 光盘iso centos1804 网络适配器 仅主机模式 显示器 自动检测 controller 内存 5.3GB 处理器 ...

  6. UDP协议测试

    UDP协议测试 我们一般想到测试连通性时第一考虑到的就是使用ping命令. 但是我们知道ping命令使用的是icmp协议,属于tcp/ip协议中的一个子协议,所以我们可以用ping或tcping命令来 ...

  7. 【Java】 WebService 校验机制

    测试环境域名 不可见 正式环境域名 不可见 1.2.安全校验凭证 accessId(授权ID) 测试/正式待定 securityKey(加密密钥) 测试/正式待定 1.3.安全校验机制 1.3.1.在 ...

  8. 【设计模式 Design Pattern】【UML】建模语言

    什么是UML图? UML-Unified Modeling Language 统一建模语言,又称标准建模语言. 是用来对软件密集系统进行可视化建模的一种语言. UML的定义包括UML语义和UML表示法 ...

  9. 【Spring-Security】Re10 Oauth2协议 P1 授权码模式 & 密码模式

    一.Oauth2协议: 第三方登录,即忘记本站密码,但是登录界面中提供了一些第三方登录,例如微信.支付宝.QQ.等等,通过第三方授权实现登录 第三方认证技术主要解决的时认证标准,各个平台的登录要遵循统 ...

  10. 预处理共轭梯度算法(Preconditioned Conjugate Gradients Method)

    预处理共轭梯度算法(Preconditioned Conjugate Gradients Method) 给出百度百科上的解释: 预处理共轭梯度法 预处理共轭梯度法是.不必预先估计参数等特点. 共轭梯 ...