前端使用 Konva 实现可视化设计器(22)- 绘制图形(矩形、直线、折线)

news2024/11/14 2:33:28

本章分享一下如何使用 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源码

示例地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2122270.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RAG 聊天机器人:用 Langchain 和 Streamlit开启与 PDF 的智能对话

与大量 PDF 文档的交互如今变得前所未有地便捷与智能。想象一下,您可以轻松与您的笔记、书籍和各种文档进行无缝对话,不再需要繁琐的手动查找和处理。 这篇文章将带您逐步构建一个基于 Multi-RAG 和 Streamlit 的 Web 应用程序,该应用程序通过 AI 驱动的聊天机器人来读取、…

【Linux 报错】SSH服务器拒绝了密码。请再试一次。(xshell)

出现该错误 可能的原因&#xff1a; 你写入的登录密码错误了&#xff0c;错误原因有&#xff1a; 1、本来输入就错误了 2、创建用户时&#xff0c;只创建了用户名&#xff0c;但密码没有重新设置 3、多人使用同一台服务器时&#xff0c;该服务器管理员&#xff08;本体&#x…

MyEclipse2020安装教程(图文)

本章教程主要记录如何在Windows上安装MyEclipse2020.。 一、下载安装包 通过网盘分享的文件&#xff1a;Myeclipse 2020.rar 链接: https://pan.baidu.com/s/1fD2P0S0GU_zJlUHTPeXP-A?pwdv71m 提取码: v71m 二、安装步骤 1、打开解压后的文件夹&#xff0c;鼠标右击【myeclip…

农产品管理与推荐系统Python+Django网页界面+计算机毕设项目+推荐算法

一、介绍 农产品管理与推荐系统。本系统使用Python作为主要开发语言&#xff0c;前端使用HTML&#xff0c;CSS&#xff0c;BootStrap等技术和框架搭建前端界面&#xff0c;后端使用Django框架处理应用请求&#xff0c;使用Ajax等技术实现前后端的数据通信。实现了一个综合性的…

威胁建模攻击树和攻击库

威胁建模攻击树和攻击库 1.攻击树概述2.创建新的攻击树&#x1f332;3.真实攻击树的案例诈骗攻击树思维导图式SSL风险攻击树 4.攻击库概述5.CAPEC攻击模式6.OWASP 1.攻击树概述 攻击树&#xff08;Attack Tree&#xff09;是一种用于分析和描述系统安全的工具&#xff0c;广泛…

独立产品灵感周刊 DecoHack #067 - 摸鱼神器与AI视频创作工具

本周刊记录有趣好玩的独立产品/设计/开发相关内容&#xff0c;每周一发布&#xff0c;往期内容同样精彩&#xff0c;感兴趣的伙伴可以到官网查看更多内容。可以邮件订阅或RSS订阅本周刊。欢迎通过 Twitter 私信推荐或投稿。 本期内容涵盖从摸鱼神器、AI视频生成&#xff0c;到乐…

【Linux 运维知识】Linux 编译后的内核镜像大小

Linux 内核镜像的大小取决于多个因素&#xff0c;包括内核的版本、启用的功能、模块的数量以及特定的编译配置。 以下是常见情况下不同内核镜像的大小范围&#xff1a; 1. 标准内核镜像大小 压缩后的内核镜像 (vmlinuz)&#xff1a; 压缩后的内核镜像文件&#xff0c;通常位于…

【西电电装实习】4. 无人机系统

文章目录 前言一、定义概念 缩写定义分类 二、性质系统结构 开源平台三、使用步骤总结参考文献 前言 西电电装实习 - 无人机系统 一、定义概念 缩写 定义 无人机&#xff08;Unmanned Aerial Vehicle&#xff0c;UAV&#xff09;&#xff0c;是无人驾驶的飞行器。它利用无…

StarRocks 培训课程重磅上线!专家出品,助你升级打怪不走弯路!

今年已过了大半&#xff0c;大家的学习进度条进展如何&#xff1f;如果你对 StarRocks 的基础知识还有疑惑&#xff0c;或在寻找系统性的学习方法&#xff0c;不必灰心&#xff0c;因为 Rocky 要来助你一臂之力啦&#xff01; &#x1f389; StarRocks Education 上线 值此 S…

LLM的指令微调新发现:不掩蔽指令

最近看到了一篇挺有意思的论文&#xff0c;叫《指令掩蔽下的指令调整》&#xff08;Instruction Tuning With Loss Over Instructions&#xff0c;https://arxiv.org/abs/2405.14394) 。 这篇论文里&#xff0c;研究者们对一个在指令微调中大家普遍接受的做法提出了疑问&#…

2024.9.10营养小题【1】

收获&#xff1a; 1、上图中第一个红框中的内容有所收获&#xff0c;首先是malloc这个函数。 2、*returnSizen*2 这条语句我觉得不存在也不影响解这道题吧&#xff0c;它的作用是给returnSize这个指针指向的那块内存赋值&#xff0c;这个值是不是不给也可以.......

启动程序时遇到0xc000007b应用程序无法正常启动问题

启动程序时遇到0xc000007b应用程序无法正常启动问题 参考链接&#xff1a; 1、https://www.bilibili.com/read/cv16283667/ 一、问题描述&#xff1a; 启动程序时遇到0xc000007b应用程序无法正常启动问题&#xff0c;问题截图如下&#xff1a; 二、问题原因&#xff1a;错误…

芯片IC的热特性和热阻

芯片IC的热特性和热阻 1.概述2.热特性基础3.热阻4.常用的热阻值5.有效散热的经验法则5.1选择合适的封装5.2尽可能大面积的PCB覆铜5.3增加铜厚5.4用散热焊盘和过孔将多层PCB连接5.5结构散热5.6散热片的合理使用5.7不要在散热走线上覆阻焊层 IC 封装的热特性对 IC 应用和可靠性是…

LSTM处理时序数据:深入解析与实战

大家好&#xff0c;我是你们的深度学习老群群。今天&#xff0c;我们来聊一聊LSTM&#xff08;长短期记忆网络&#xff09;是如何处理时序数据并得到预测结果的。LSTM作为循环神经网络&#xff08;RNN&#xff09;的一种变体&#xff0c;因其能够有效捕捉长期依赖关系&#xff…

nova Flip的AI技能点拉满,这些趣味且实用的功能你知道几个?

随着科技的蓬勃发展&#xff0c;人工智能已经渗透到我们日常生活的各个领域&#xff0c;“AIGC”“AI大模型”成为时下的热门词汇。手机作为承接AI革新技术的重要载体&#xff0c;不仅能够大大提升用户的工作效率&#xff0c;也带来了自然、流畅的操作交互体验。 nova Flip…

RocketMQ搭建集群监控平台

一、概述 RocketMQ有一个对其扩展的开源项目incubator-rocketmq-externals&#xff0c;这个项目中有一个子模块叫rocketmq-console&#xff0c;这个便是管理控制台项目了&#xff0c;先将incubator-rocketmq-externals拉到本地&#xff0c;因为我们需要自己对rocketmq-console…

win11任务栏颜色怎么全透明?简单四招设置透明任务栏,保姆级教程!

在日常使用win11时&#xff0c;任务栏是我们与电脑互动的重要窗口。随着越来越多的用户希望将桌面环境打造成一个既美观又个性化的空间&#xff0c;任务栏的外观便成为了许多人关注的重点。很多用户发现&#xff0c;尽管win11系统提供了半透明的任务栏&#xff0c;但还是渴望实…

AlphaNovel的身份验证失败了..........

我的AlphaNovel的这个身份验证失败了,不知道失败原因是什么... 前两周在网上看到这个项目,在国外这个网站搬运国内小说,但是前提是要通过这个身份验证,可是我等了十多天,结果身份验证失败了,有也在做这个的同志吗? 你们身份验证怎么样

告别繁琐,IsMyHdOK硬盘测速,即刻享受科技便利

快节奏的生活因科技而精彩纷呈&#xff0c;它赋予我们超越时空的能力&#xff0c;让工作与家庭的天平在忙碌中依然保持平衡——而面对数据爆炸的时代&#xff0c;硬盘作为数据存储与交换的核心部件&#xff0c;其性能直接影响到我们的工作效率和体验。正是在这样的背景下&#…

【2024下半年最新!】端点安全管理系统是干啥的?10款哈游的端点安全管理系统推荐!

一、端点安全管理系统是干什么的&#xff1f; 端点安全管理系统&#xff08;Endpoint Security Management System, EMS&#xff09;是一种全面、高效的网络安全管理工具&#xff0c;旨在保护企业网络和数据的安全性。以下是其主要功能和作用&#xff1a; 端点检测和识别&…