数据可视化-Canvas

news2024/12/26 9:33:16

Canvas

Canvas API 主要聚焦于 2D 图形。当然也可以使用<canvas>元素对象的 WebGL API 来绘制 2D 和 3D 图形,可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理。

  • Canvas非常适合图像密集型的游戏开发,适合频繁重绘许多的对象。
  • 能够以 .png 或 .jpg 格式保存结果图像,适合对图片进行像素级的处理。
  • 在移动端可以能会因为Canvas数量多,而导致内存占用超出了手机的承受能力,导致浏览器崩溃。
  • Canvas 是由一个个像素点构成的图形,放大会使图形变得颗粒状和像素化,导致模糊。

canvas

<canvas> 标签只有width和height属性,没有设置宽度和高度时,canvas 会初始化宽为300px 和高为 150px。

<img>元素不同,<canvas> 元素必须需要结束标签 </canvas>。如结束标签不存在,则文档其余部分会被认为是替代内容,将不会显示出来。

<canvas id="myCanvas" width="200" height="200"></canvas>

测试 canvas.getContext() 方法的存在,可以检查浏览器是否支持Canvas

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

if (ctx) {
  console.log('Canvas is supported!');
} else {
  console.log('Canvas is not supported!');
}

绘制一个矩形

<canvas id="canvas" width="500" height="500"></canvas>
<script>
        const canvasEl = document.getElementById('canvas');
        const ctx = canvasEl.getContext('2d');
        ctx.fillRect(0, 0, 100, 50);
</script>

坐标空间

  • <canvas>元素默认被网格所覆盖,通常来说网格中的一个单元相当于 canvas 元素中的一像素。
  • 该网格的原点位于坐标 (0,0) 的左上角。所有元素都相对于该原点放置。

图形路径

Canvas 绘图的方法主要有两种:路径绘图和像素绘图。

  1. 路径绘图:路径绘图是通过一系列的路径命令来绘制图形。路径绘图可以用来绘制各种各样的图形,比如线条、矩形、圆形、多边形等等。Canvas 提供了一系列的路径绘图 API,比如 beginPathmoveTolineTorectarc 等等。
  2. 像素绘图:像素绘图是通过直接操作像素来绘制图形。像素绘图可以用来绘制各种各样的图形,比如图片、文字、图标等等。Canvas 提供了一系列的像素绘图 API,比如 drawImagefillTextgetImageDataputImageData 等等
  • 需要注意的是,路径绘图和像素绘图是两种不同的绘图方式,它们各有优缺点,应根据具体情况来选择合适的绘图方式。在实际开发中,我们可以根据需求来选择合适的绘图方式,并进行适当的优化和调整。

Canvas 绘图的矩形方法:

  • fillRect(x, y, width, height): 绘制一个填充的矩形
  • strokeRect(x, y, width, height): 绘制一个矩形的边框
  • clearRect(x, y, width, height): 清除指定矩形区域,让清除部分完全透明

Canvas 绘图的路径方法:

  • 图形的基本元素是路径。路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的点的集合。
  • 路径是可由很多子路径构成,这些子路径都是在一个列表中,列表中所有子路径(线、弧形等)将构成图形。

使用路径绘制图形的步骤

  1. 创建路径:使用 beginPath 方法来创建一个新的路径。每次调用 beginPath 方法都会创建一个新的路径,之前的路径会被清除。
  2. 移动画笔:使用 moveTo 方法来移动画笔到指定的坐标点。调用 moveTo 方法后,画笔会停留在指定的坐标点,等待下一次的路径命令。
    • moveTo(x, y)
      • 将笔移动到指定的坐标 x 、 y 上
  3. 然后使用画图命令去画出路径( arc 、lineTo )
    • lineTo(x, y)
      • 调用 lineTo 方法后,画笔会从当前位置绘制一条直线到指定的坐标点,并停留在指定的坐标点,等待下一次的路径命令。
    • ctx.rect(x, y, width, height);
      • 使用 rect 方法来绘制一个矩形。调用 rect 方法后,画笔会绘制一个矩形,并停留在矩形的右下角,等待下一次的路径命令。
    • arc(x, y, radius, startAngle, endAngle, anticlockwise);
      • x、y:为绘制圆弧所在圆上的圆心坐标
      • radius:为圆弧半径,弧度=( Math.PI / 180 ) * 角度
      • startAngle、endAngle:该参数用弧度定义了开始以及结束的弧度。这些都是以 x 轴为基准。
      • anticlockwise:为一个布尔值。为 true ,是逆时针方向,为false,是顺时针方向,默认为false。
      • 调用 arc 方法后,画笔会绘制一个圆形,并停留在圆形的结束点,等待下一次的路径命令。
  4. 闭合路径:使用 closePath 方法来闭合路径。调用 closePath 方法后,画笔会从当前位置绘制一条直线到路径的起始点,并停留在起始点,等待下一次的路径命令。
  5. 绘制路径:使用 strokefill 方法来绘制路径。调用 stroke 方法可以绘制路径的线条,调用 fill 方法可以填充路径的内部。
<canvas id="myCanvas" width="500" height="500"></canvas>
<script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');

    ctx.beginPath();
    ctx.moveTo(50, 50);
    ctx.lineTo(150, 50);
    ctx.lineTo(150, 150);
    ctx.lineTo(50, 150);
    ctx.closePath();
    // 绘制线条
    ctx.lineWidth = 5;
    ctx.strokeStyle = '#f00';
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(200, 200);
    ctx.lineTo(300, 200);
    ctx.lineTo(300, 300);
    ctx.closePath();
  	// 填充区域
    ctx.fillStyle = '#00f';
    ctx.fill();
</script>

在这里插入图片描述

样式绘制

色彩 Colors

  • 填充样式:使用 fillStyle 属性来设置填充的颜色或渐变对象
  • strokeStyle 是 Canvas 的 API 之一,用于设置描边的颜色或渐变对象。
  • 默认情况下,线条和填充颜色都是黑色

全局透明度: globalAlpha 属性

  • 这个属性影响到 canvas 里所有图形的透明度,来设置全局透明度
  • 取值范围为 0 到 1,表示透明度从完全透明到完全不透明的过渡
  • 有效的值范围是 0.0(完全透明)到 1.0(完全不透明),默认是 1.0。

线条样式

  • 使用 lineWidth 属性来设置线条的宽度
    • 线宽是指给定路径的中心到两边的粗细。换句话说就是在路径的两边各绘制线宽的一半
  • 使用 lineCap 属性来设置线条的端点样式
    • butt 截断,默认是 butt。
    • round 圆形
    • square 正方形
  • 使用 lineJoin 属性来设置线条的连接样式
    • round 圆形
    • bevel 斜角
    • miter 斜槽规,默认是 miter。
  • 使用 miterLimit 属性来设置斜接连接的限制比例
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 设置线条样式
ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.miterLimit = 10;

// 设置全局透明度
ctx.globalAlpha = 0.5;

// 绘制矩形
ctx.fillRect(50, 50, 100, 100);

绘制文本

Canvas 提供了多种 API 来绘制文本,包括 fillTextstrokeText

  • fillText

    • 方法接受三个参数:要绘制的文本字符串、文本的 x 坐标和 y 坐标

    • const canvas = document.getElementById('myCanvas');
      const ctx = canvas.getContext('2d');
      
      // 设置字体样式
      ctx.font = '30px Arial';
      
      // 设置文本颜色
      ctx.fillStyle = '#f00';
      
      // 绘制文本
      ctx.fillText('Hello, world!', 50, 50);
      
  • strokeText

    • 方法接受三个参数:要绘制的文本字符串、文本的 x 坐标和 y 坐标。

文本的样式

  • Canvas 提供了多种 API 来设置文本的样式,包括 fonttextAligntextBaseline

  • const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // 设置字体样式
    ctx.font = '30px Arial';
    
    // 设置文本颜色
    ctx.fillStyle = '#f00';
    
    // 设置文本对齐方式
    ctx.textAlign = 'center';
    
    // 设置文本基线
    ctx.textBaseline = 'middle';
    
    // 绘制文本
    ctx.fillText('Hello, world!', 200, 100);
    

绘制图片

Canvas 提供了 drawImage 方法来绘制图片。drawImage 方法接受三个参数:要绘制的图片对象、图片的 x 坐标和 y 坐标。

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 创建图片对象
const img = new Image();
img.src = 'image.png';

// 等待图片加载完成后再绘制
img.onload = function() {
  // 绘制图片
  ctx.drawImage(img, 50, 50);
};

需要注意的是,绘制图片时需要等待图片加载完成后再进行绘制,否则可能会出现绘制不成功的情况。另外,绘制图片时需要指定图片的位置,可以使用 drawImage 方法的第二个和第三个参数来指定图片的位置。

图片的来源,canvas 的 API 可以使用下面这些类型中的一种作为图片的源

  • 从本地文件获取图片:

    • const img = new Image();
      img.src = 'image.png';
      
  • 从网络获取图片:

    • const img = new Image();
      img.src = 'https://example.com/image.png';
      
  • 从视频截图获取图片:

    • const video = document.getElementById('myVideo');
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      
      // 在视频播放时截取当前帧的图像
      video.addEventListener('play', function() {
        setInterval(function() {
          // 将视频当前帧绘制到 Canvas 上
          ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
      
          // 获取 Canvas 上的图像数据
          const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      
          // 创建图片对象
          const img = new Image();
          img.src = imageData;
      
          // 绘制图片
          ctx.drawImage(img, 50, 50);
        }, 1000 / 30);
      });
      

绘画状态

在 Canvas 中,可以使用状态保存和恢复 API 来保存和恢复绘画状态。状态包括当前的变换矩阵、剪切区域、样式等等。

每一次 ctx.save 都会将当前的样式存储在一个栈中,恢复的时候先恢复最后加入的

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 保存绘画状态
ctx.save();

// 设置绘画状态
ctx.fillStyle = '#f00';
ctx.translate(50, 50);
ctx.rotate(Math.PI / 4);

// 绘制矩形
ctx.fillRect(0, 0, 100, 100);

// 恢复绘画状态
ctx.restore();

// 绘制矩形
ctx.fillRect(150, 50, 100, 100);

在上面的示例中,我们首先在 HTML 中创建了一个 Canvas 元素,并设置了它的宽度和高度。然后,在 JavaScript 中,我们获取了 Canvas 元素的上下文对象 ctx,并使用 Canvas 的 API 设置了绘画状态,包括填充样式、变换矩阵等等。接着,我们使用 save 方法保存了当前的绘画状态,然后绘制了一个矩形。最后,我们使用 restore 方法恢复了之前保存的绘画状态,并绘制了另一个矩形。

Transform

在 Canvas 中,可以使用变换矩阵来对绘制的图形进行变换,包括平移、旋转、缩放等等。Canvas 提供了多个 API 来设置变换矩阵,包括 translaterotatescale 等等。

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 绘制矩形
ctx.fillStyle = '#f00';
ctx.fillRect(50, 50, 100, 100);

// 平移矩形
ctx.translate(100, 0);

// 旋转矩形
ctx.rotate(Math.PI / 4);

// 缩放矩形
ctx.scale(0.5, 0.5);

// 绘制矩形
ctx.fillStyle = '#0f0';
ctx.fillRect(50, 50, 100, 100);

注意事项:

  • 在做变形之前先调用 save 方法保存状态是一个良好的习惯。
  • 大多数情况下,调用 restore 方法比手动恢复原先的状态要简单得多。
  • 如果在一个循环中做位移但没有保存和恢复canvas状态,很可能到最后会发现有些东西不见了,因为它很可能已超出canvas画布以外了。
  • 形变需要在绘制图形前调用。

绘制动画

canvas可能最大的限制就是图像一旦绘制出来,它就是一直保持那样了,如需要执行动画,不得不对画布上所有图形进行一帧一帧的重绘。

画出一帧动画的基本步骤(如要画出流畅动画,1s 需绘60帧)

  • 第一步:用 clearRect 方法清空 canvas ,除非接下来要画的内容会完全充满 canvas(例如背景图),否则你需要清空所有。
  • 第二步:保存 canvas 状态,如果加了 canvas 状态的设置(样式,变形之类的),又想在每画一帧之时都是原始状态的话,你需要先保存一下,后面再恢复原始状态。
  • 第三步:绘制动画图形(animated shapes) ,即绘制动画中的一帧。
  • 第四步:恢复 canvas 状态,如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。

如果想要更加平稳和更加精准的定时执行某个任务的话,可以使用requestAnimationFrame函数

时钟案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .clock {
        width: 300px;
        height: 300px;
        margin: 10px;
        border-radius: 50px;
        background-color: black;
      }
    </style>
  </head>
  <body>
    <div class="clock">
      <canvas id="tutorial" width="300" height="300">
        该浏览器不支持Canvas,请更新你的浏览器
      </canvas>
    </div>
    <script>
      window.onload = function () {
        var canvas = document.getElementById("tutorial");
        if (canvas.getContext) {
          var ctx = canvas.getContext("2d");
        }
        requestAnimationFrame(draw);

        function draw() {
          ctx.clearRect(0, 0, 300, 300);

          ctx.save();
          ctx.translate(150, 150); // 移动坐标点(抽取)
          // 拿到时间
          var time = new Date();
          var hours = time.getHours();
          var min = time.getMinutes();
          var second = time.getSeconds();

          drawBg();
          drawText();
          drawHours(hours, min, second);
          drawMinute(hours, min, second);
          drawSecond(hours, min, second);
          drawCircle();
          drawHoursRule();
          drawMinuteRule();
          ctx.restore();

          requestAnimationFrame(draw);
        }

        function drawBg() {
          ctx.save();
          // ctx.translate(150, 150); // 移动坐标点(抽取)
          ctx.fillStyle = "white";
          ctx.beginPath();
          ctx.arc(0, 0, 130, 0, Math.PI * 2);
          ctx.fill();
          ctx.restore();
        }

        function drawText() {
          ctx.save();
          // ctx.translate(150, 150); //(抽取)
          ctx.font = "30px fangsong";
          ctx.textBaseline = "middle";
          ctx.textAlign = "center";
          //  x = Math.cos(  Math.PI * 2 / 12  * i  )  *  R
          //  y = Math.sin(  Math.PI * 2 / 12  * i  )  * R
          var timeNumbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
          for (var i = 0; i < 12; i++) {
            var x = Math.cos(((Math.PI * 2) / 12) * i) * 100;
            var y = Math.sin(((Math.PI * 2) / 12) * i) * 100;
            ctx.fillText(timeNumbers[i], x, y);
          }
          ctx.restore();
        }

        function drawHours(hours, min, second) {
          // 3.绘制时针
          ctx.save();
          ctx.lineWidth = 5;
          ctx.lineCap = "round";
          // ctx.translate(150, 150); //(抽取)
          // 1小时 1分 1 秒 的弧度
          // ((Math.PI * 2) / 12) * 1h => 分成 12 份
          // ((Math.PI * 2) / 12 / 60) * 1m =>分成 60份
          // ((Math.PI * 2) / 12 / 60 / 60) * 1s => 分成 60份
          ctx.rotate(
            ((Math.PI * 2) / 12) * hours +
              ((Math.PI * 2) / 12 / 60) * min +
              ((Math.PI * 2) / 12 / 60 / 60) * second
          );
          ctx.beginPath();
          ctx.moveTo(0, 0);
          ctx.lineTo(0, -50);
          ctx.stroke();
          ctx.restore();
        }

        function drawMinute(hours, min, second) {
          // 4.绘制分针
          ctx.save();
          ctx.lineWidth = 3;
          ctx.lineCap = "round";
          // ctx.translate(150, 150); //(抽取)
          // 1分 1 秒 的弧度

          // ((Math.PI * 2) / 60) * 1m =>分成60份
          // ((Math.PI * 2) / 60 / 60) * 1s => 分成 60份

          ctx.rotate(
            ((Math.PI * 2) / 60) * min + ((Math.PI * 2) / 60 / 60) * second
          );
          ctx.beginPath();
          ctx.moveTo(0, 0);
          ctx.lineTo(0, -70);
          ctx.stroke();
          ctx.restore();
        }

        function drawSecond(hours, min, second) {
          // 5.绘制秒针
          ctx.save();
          ctx.lineWidth = 2;
          ctx.lineCap = "round";
          ctx.strokeStyle = "red";
          // ctx.translate(150, 150); //(抽取)
          // 1 秒 的弧度
          // ((Math.PI * 2)  / 60) * 1s => 分成 60份
          ctx.rotate(((Math.PI * 2) / 60) * second);
          ctx.beginPath();
          ctx.moveTo(0, 0);
          ctx.lineTo(0, -90);
          ctx.stroke();
          ctx.restore();
        }

        function drawCircle() {
          // 6.绘制圆环
          ctx.save();
          // ctx.translate(150, 150);

          ctx.beginPath();
          ctx.arc(0, 0, 8, 0, Math.PI * 2);
          ctx.fill();

          ctx.beginPath();

          ctx.fillStyle = "gray";
          ctx.arc(0, 0, 5, 0, 2 * Math.PI);
          ctx.fill();
          ctx.restore();
        }

        function drawHoursRule() {
          // 7.绘制时刻度
          ctx.save();
          ctx.lineWidth = 3;
          // ctx.translate(150, 150);
          // 时的刻度
          for (var j = 0; j < 12; j++) {
            ctx.rotate(((Math.PI * 2) / 12) * 1);
            ctx.beginPath();
            ctx.moveTo(0, -130);
            ctx.lineTo(0, -122);
            ctx.stroke();
          }
          ctx.restore();
        }

        function drawMinuteRule() {
          // 8.绘制分刻度
          ctx.save();
          ctx.lineWidth = 1;
          // ctx.translate(150, 150);
          // 时的刻度
          for (var j = 0; j < 60; j++) {
            ctx.rotate(((Math.PI * 2) / 60) * 1);
            ctx.beginPath();
            ctx.moveTo(0, -130);
            ctx.lineTo(0, -125);
            ctx.stroke();
          }
          ctx.restore();
        }
      };
    </script>
  </body>
</html>

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

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

相关文章

opencv膨胀腐蚀

OpenCV 是一个开源的计算机视觉库&#xff0c;它包含了许多图像处理的功能&#xff0c;其中膨胀和腐蚀是两种常用的形态学操作。 膨胀&#xff08;Dilation&#xff09;&#xff1a;膨胀操作是将图像中的高亮区域&#xff08;白色像素&#xff09;扩张&#xff0c;从而填充低亮…

火车票和机票已支持数电票,泛微齐业成提供数电票全流程管理方案

数电票已经成为趋势 01扩大全面数字化的电子发票试点范围 2023年以来&#xff0c;河南、深圳等多省市税务局发布《关于开展全面数字化的电子发票试点工作的公告》&#xff0c;进一步扩大了全面数字化的电子发票试点范围&#xff0c;在政府公告、文件描述中&#xff0c;“数电…

轻松提高SketchUp技能的15个简单技巧

SketchUp一直是设计界有名的3d建模软件之一&#xff0c;其直观的工作工具、开源库和无数的插件使 SketchUp 易于使用。通常&#xff0c;它被用来让孩子们接触建筑。其用户友好的界面使其成为初学者的绝佳应用程序。它包含一系列功能&#xff0c;能够以高效和突出的方式为学生和…

雪花算法工具类介绍

简介 雪花 &#xff08;SnowFlake &#xff09;算法是一种分布式唯一ID生成算法&#xff0c;可以生成全局唯一的ID标识符&#xff0c;就像自然界中雪花一般没有相同的雪花。它的核心思想是将一个64位的整数分成4部分&#xff0c;分别是&#xff1a; 1位标识符&#xff1a;即最…

关于ERP系统,你可能不知道的10件事

谈到ERP系统&#xff0c;大多数人只是考虑ERP日常管理的核心功能&#xff0c;即财务、销售、采购、库存、生产和分销。保持对这些关键领域的控制对任何企业的成功都是不可或缺的。但这些只是冰山一角&#xff0c;如果深入挖掘ERP系统&#xff0c;你可能会惊讶于它的其他功能。以…

vue3 - 【完整源码】实现容器用鼠标拖曳功能,将容器 “限制在指定范围内“ 鼠标拖拽移动并拿到横纵坐标(详细示例源码及注释,一键复制开箱即用)

效果图 在vue3网页项目中,实现将一个容器设置为鼠标可拖动拖曳效果(并限制在边界内不可拖出去),并且拖拽时自动获取横纵坐标以及相关的事件,基础的示例可自定义为任何你想要的效果。 你可以直接下方效果图的示例源代码,配合详细的原理描述及代码注释保证可用!稍微改改就…

SIEM(安全信息与事件管理)的重要性及 Log360 的卓越功能

摘要&#xff1a;随着网络安全威胁的不断增加&#xff0c;企业和组织对于安全信息与事件管理&#xff08;SIEM&#xff09;解决方案的需求日益迫切。本文将重点介绍 SIEM 的重要性&#xff0c;并详细探讨 ManageEngine 公司旗下的 Log360 解决方案所提供的卓越功能和优势。 引…

胶片打印、排版、自助打印(二)

一、DICOM打印的两种类型 灰度图像打印&#xff1a; 彩色图像打印&#xff1a; 通常情况下RGB类型DICOM图像包含如下的内容&#xff1a; (0028,0010)Rows 图像的高度 (0028,0011)Columns 图像的宽度 (0028,0030)Pixel Spacing 图像像素间距&#xff0c;读取Pixel Data的时候…

Niagara——概述

Niagara是最新一代VFX系统&#xff0c;无需程序员的帮助&#xff0c;即可创建丰富多彩的效果&#xff1b;高级用户还可自定义模块modules&#xff1b; 核心组件 SystemsEmittersModulesParameters systems systems是构建效果容器&#xff0c;创建不同类型效果元素以实现整体效果…

Python从多个表格中随机抽取数据加以处理后合并全部数据

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;基于其中每一个文件&#xff0c;随机从其中选取一部分数据&#xff0c;并将全部文件中随机获取的数据合并为一个新的Excel表格文件的方法。 首先&#xff0c;我们来明确一下本文的具体需求。…

免交互expect

免交互 一、expect1、环境安装2、基本命令2.1 脚本解释器2.2 spawn&#xff08;跟踪&#xff09;2.3 expect &#xff08;捕捉&#xff09;2.4 send&#xff08;发送&#xff09;2.5 结束符2.7 exp_continue2.8 send user2.9 接收参数 二、ssh无交互登录到远程服务器1、登录完成…

Android 自定义弹窗 附带搜索过滤功能

项目场景&#xff1a; 前两天要求在项目中添加个小功能&#xff0c;今天正好有时间随手写了一个小demo&#xff0c;过程分享给大家。以后如果有此类需求可直接移植使用。 需求是因为在下拉列表中选择一个项作为数据显示在界面上&#xff0c;但是所有的选项很多&#xff0c;下翻…

软件著作权容易搞吗?

没有代码、材料&#xff0c;只有一个软件名字就能拿证&#xff0c;你说容易不… 当然这是对我们软著一级代理来说&#xff0c;每年申请下证几千个软著。下面说说下证要点给大家避坑。人群覆盖高新企业、大学生、大学老师、互联网公司。 软件著作权想要轻松下证&#xff0c;必…

《微服务实战》 第十六章 Spring cloud stream应用

前言 https://github.com/spring-cloud/spring-cloud-stream-binder-rabbit 官方定义Spring Cloud Stream是一个构建消息驱动微服务的框架。应用程序通过inputs或者outputs来与Spring Cloud Stream中binder对象交互。通过我们配置来binding(绑定),而Spring Cloud Stream的bin…

lwIP更新记06:申请 TCP 控制块(tcp_alloc)

从 lwIP-2.0.0 开始&#xff0c;申请 tcp_pcb 控制块的逻辑发生了变化。 每个 tcp 连接都必须有一个 PCB 控制块 &#xff0c;使用函数 tcp_new() 申请 PCB 控制块。tcp_new 函数代码如下所示&#xff1a; /*** Creates a new TCP protocol control block but doesnt place it…

进阶篇丨链路追踪(Tracing)很简单:常见问题排查

作者&#xff1a;涯海 经过前面多篇内容的学习&#xff0c;想必大部分同学都已经熟练掌握分布式链路追踪的基础用法&#xff0c;比如回溯链路请求轨迹&#xff0c;定位耗时瓶颈点&#xff1b;配置核心接口黄金三指标告警&#xff0c;第一时间发现流量异常&#xff1b;大促前梳…

公司刚来的测试,00后真卷,上班还没2年,跳到我们公司起薪20k....

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。 这不&#xff0c;前段时间我们公司来了个00后&#xff0c;工作都没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了…

neo4j图形数据库

目录 1. neo4j简介1.1 什么是图形数据库1.2 什么是neo4j1.3 neo4j的特性1.4neo4j的优点1.5 neo4j的构建元素 2. 安装部署2.1 环境说明2.2 下载安装包2.3 解压安装包2.4 配置安装jdk环境2.5 配置neoj4全局变量2.6 修改neo4j配置文件2.7 服务基本操作2.8 测试访问 3. 使用DBeaver…

上门洗车小程序软件开发所需要的功能有哪些呢?

相信很多企业及投资者都想开发一款属于自己的小程序系统。那么一款专业好用的上门洗车小程序软件开发所需要的功能有哪些呢&#xff1f; 1. 用户注册与登录。 用户可以通过手机号码或微信账号进行注册和登录。注册后可以查看历史订单、评价技师、参加活动等。 …

浅析EasyCVR视频能力在自然灾害风险预警场景中的应用意义

一、方案背景 我国是自然灾害多发的国家&#xff0c;夏季也是灾害多发季节&#xff0c;山洪、泥石流、洪涝、冰雹、飓风、地震等自然灾害每年都给国家经济带来巨大的损失。建设自然灾害风险预警视频监控系统&#xff0c;实现对自然灾害的可视化预警监测和监管&#xff0c;并提…