Canvas初学踩坑

对于Canvas的使用,是直接使用原生的还是使用封装的类库比如konvajs等,各有什么优缺点

使用Canvas原生API与使用封装的类库(如KonvaJS)各有优缺点,具体选择取决于项目的具体需求和开发者的偏好。以下是两种方式的主要优缺点:

使用Canvas原生API:

优点:

  1. 灵活性高:原生API提供了底层访问权限,可以完全控制绘图过程中的每一个细节,对于需要高度定制化或性能优化的场景非常有用。
  2. 学习成本较低:虽然原生API功能相对基础,但对于简单的图形绘制、动画制作等任务来说,理解和掌握API并不复杂。
  3. 轻量级:直接使用原生API不会引入额外的库文件,有助于减小项目体积。

缺点:

  1. 抽象层级低:原生API较为底层,对于复杂的图形处理、交互事件监听等操作可能需要编写较多代码。
  2. 缺乏高级特性:例如,不提供现成的分层、组、拖拽、变形等高级图形操作支持,需要开发者自行实现。
  3. 维护成本较高:随着项目规模扩大和需求变更,自定义实现的绘图逻辑可能会变得难以维护。

使用封装的类库(如KonvaJS):

优点:

  1. 高级特性丰富:提供了诸如分层、图形组合、拖放、变换、动画等功能,极大简化了复杂图形处理和交互设计。
  2. 易于维护:封装好的类库通常具有良好的结构和文档,便于后续维护和扩展。
  3. 提高开发效率:通过调用封装好的API方法,能够快速实现各种图形和交互效果,节省开发时间。

缺点:

  1. 学习成本:相比于原生API,可能需要花费更多时间学习类库的API和使用方法。
  2. 依赖性:引入第三方库意味着增加了项目的依赖性,若库存在bug或更新不及时,可能影响到项目进度。
  3. 资源开销:虽然大多数成熟的类库会尽力优化性能,但相比原生API,间接调用可能带来一定的性能损耗,增加项目总体大小。

总结而言,如果项目对Canvas图形的需求比较简单且不需要太多交互,或者对性能要求极高,可以直接使用原生Canvas API。而对于需要大量图形处理、动画制作和复杂交互设计的项目,使用封装的类库如KonvaJS将更高效且便于维护。

为什么我用canvas的arc方法画的圆是椭圆

写错了canvas的样式,写成了内联样式(只在css里面设置width和height样式也会有问题)

js 复制代码
<canvas ref="cRef" class="canvas-page" style="width: 800px;height: 800px"></canvas>

正确写法为

js 复制代码
<canvas ref="cRef" class="canvas-page" width="800" height="800"></canvas>

建议永远不要使用css属性为canvas设置宽高

chatgpt 解答

如果使用 canvasarc() 方法画出来的圆是椭圆,可能是因为你的 canvas 元素的宽高比不是 1:1,造成了绘制出来的圆形变形。

解决方法是在设置 canvas 元素的宽高时,让宽和高保持一致,例如:

html 复制代码
<canvas id="myCanvas" width="300" height="300"></canvas>

或者在绘制圆形之前调用 scale() 方法将 canvas 进行缩放,保持宽高比例一致,例如:

js 复制代码
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// 缩放宽高比例
const scale = window.devicePixelRatio;
canvas.width = 300 * scale;
canvas.height = 300 * scale;
ctx.scale(scale, scale);

// 绘制圆形
ctx.beginPath();
ctx.arc(150, 150, 100, 0, 2 * Math.PI);
ctx.stroke();

上述代码中,通过 window.devicePixelRatio 获取设备的像素比例,对 canvas 进行缩放,使得在高分辨率屏幕上绘制出来的圆形更加清晰。

Canvas图形拖动效果实现改进版教程

blog.csdn.net/qq_40734247...

canvas标签必须要设置宽高属性,否则图片可能模糊

必须要给canvas标签设置宽高,而且不能使用或者说是不能仅使用css设置

js 复制代码
// 原生的方法必须要给canvas设置宽高,否则会出现图片不清晰的问题!!!
const { width:canvasWidth,height:canvasHeight } = container.getBoundingClientRect();
canvasRef.value.width = canvasWidth;
canvasRef.value.height = canvasHeight;

const ctx = container.getContext('2d');
const img = new Image();
const { url } = imageInfo.value;
img.src = url || testImg;
img.onload = function () {
  const imgWidth = img.width;
  const imgHeight = img.height;
  const { drawWidth, drawHeight } =
   getDrawImageInfo(imgWidth, imgHeight, canvasWidth, canvasHeight);

  const x = (canvasWidth - drawWidth) / 2;
  const y = (canvasHeight - drawHeight) / 2;

  ctx.drawImage(img, x, y, drawWidth, drawHeight);
};

使用event.key属性来监听键盘按键

在现代浏览器中,使用event.key属性来监听键盘按键是更好的做法。这是因为event.keyCode已经被弃用,并且在不同的浏览器和设备上可能会有不同的行为。

根据MDN文档:

event.keyCode: 这个属性已经废弃,不推荐使用,因为它对于同一字符在不同布局下可能返回不同的值。 event.key: 这是推荐使用的属性,它返回一个表示按下的实际键的字符串,不受当前布局的影响。 所以,在监听Escape键时,你应该这样写:

js 复制代码
document.addEventListener('keydown', function(event) {
  if (event.key === 'Escape') {
    // 处理Esc键按下事件
    console.log('Escape key pressed');
  }
});

这种方式可以提供更好的兼容性和跨平台一致性。

Keycode对照表

常用单词表

oval  椭圆

hexagon 六角形

Best_Practices 最佳实践

推荐博客

带你快速玩转canvas(8)非常用API的说明集

dandelioncloud.cn/article/det...

图片标注记录

分层思路

背景是div

图片是单独一层canvas

未选中的标注框是一层canvas

选中的标注框是一层canvas

toolTip也是div

在图片上进行标注区域,通常会在mousedown事件时添加锚点更为合适

原因如下:

  1. 实时反馈:用户在按下鼠标按钮时(mousedown),可以立即看到标注的开始或锚点的创建,这提供了更好的交互体验和实时反馈。
  2. 用户意图明确:当用户有意图创建一个标注区域时,mousedown事件更能准确地捕捉到这个意图。click事件只有在鼠标按下并释放(mouseup)后才会触发,此时用户可能已经移动了鼠标,从而导致锚点位置不精确。
  3. 拖拽操作支持:如果要支持拖拽创建标注区域,mousedown是拖拽动作的起始阶段,这时添加锚点有利于后续mousemove事件中动态更新标注形状的位置和大小。
  4. 流畅性:对于连续标注或多边形等复杂标注,mousedown事件能够更流畅地支持用户不断添加新的锚点而无需每次都完全抬起鼠标再点击。

示例代码(基于Konva.js):

js 复制代码
let layer = new Konva.Layer();
let image = new Konva.Image({ ... });
layer.add(image);

// 创建一个数组来存储锚点
let anchors = [];

layer.on('mousedown', function (e) {
  if (!isDraggingAnchor && !e.target.isDragging()) { // 防止与已有锚点的拖拽冲突
    let anchor = new Konva.Circle({
      x: e.x,
      y: e.y,
      radius: 5,
      fill: 'red',
      stroke: 'black'
    });

    layer.add(anchor);
    anchors.push(anchor);

    // 可能需要关联锚点与线或其他图形以形成标注区域
    // ...
  }
});

// 之后处理mousemove和mouseup事件以实现拖拽和最终确定标注区域

mouseup:当用户完成拖拽操作或者放置最后一个锚点时,释放鼠标按钮(mouseup)是一个常见的触发结束标注的时机。这可以用于标记用户已经完成了对某个区域的选择。

不能设置 在mouseup的时候结束放置最后一个锚点,因为若是多边形的话,需要点击多个点,一次标注过程中会有多次mouseup

规定是 左键单击绘制,右键闭合绘制,ESC键取消绘制。 并且标注过程中要避免切换标注工具,防止标注了一半,还没有闭合选框,就切换了工具。

编辑工具: 鼠标悬浮在非标注框上时,提示:左键选取标注框,T键切换标注模式 鼠标悬浮在标注框上时,提示:拖拽调整标注框,Delete删除选中框

鼠标按在非标注框区域,可以移动整个画布, 鼠标按在标注区域,只可移动标注框。且标注框不可超出图片的有效区域。

前端编程开发中,如果需要判断一个矩形或者圆形是否在一个矩形图片内,只需要找到 矩形或者圆形的外接矩形,判断外接矩形是否在矩形图片内即可,这种思路有问题吗

你提到的思路是合理的,并且在某些情况下是可行的。通过判断外接矩形是否在矩形图片内,你可以简化碰撞检测的过程,特别是当你处理的图形是矩形或圆形时。

对于矩形来说,外接矩形就是其本身,因此你只需要判断矩形的四个边是否在目标矩形内。

对于圆形来说,外接矩形是一个包围圆的最小矩形。你可以检查这个外接矩形是否在目标矩形内,然后再进一步判断圆形是否和目标矩形有交集。

这种方法的主要优点是简单,特别是对于矩形来说,它直接可以用矩形的坐标和大小进行判断。然而,在某些情况下,这种方法可能并不准确,特别是当你处理的图形更为复杂时。

如果你的应用场景中图形较为复杂,或者需要更精确的碰撞检测,可能需要使用更复杂的算法或数学计算,比如点是否在多边形内、两个任意形状之间的交集等。这通常需要更高级的数学和计算机图形学知识。

假如组里有个矩形,然后拖拽组,矩形的坐标怎么算,用文字描述即可。比如是否是 矩形的坐标为 组的相对位置 + 矩形的相对位置 = 矩形的绝对位置?

当一个矩形(或任何形状)被添加到一个组时,它的坐标是相对于该组的坐标。当你拖拽整个组时,组的坐标会发生变化,从而影响组内所有形状的相对位置。

用文字描述的话,矩形的绝对位置可以通过以下方式计算:

  1. 矩形的绝对位置 X 坐标:

    • 如果你直接使用矩形的 x() 方法,得到的是相对于组的 X 坐标。
    • 如果你使用 getAbsolutePosition().x,得到的是相对于舞台的绝对 X 坐标。
  2. 矩形的绝对位置 Y 坐标:

    • 如果你直接使用矩形的 y() 方法,得到的是相对于组的 Y 坐标。
    • 如果你使用 getAbsolutePosition().y,得到的是相对于舞台的绝对 Y 坐标。

矩形的绝对位置=组的绝对位置+矩形的相对位置

这是正确的表达。矩形的绝对位置等于组的绝对位置加上矩形的相对位置。简而言之,它是组的位置和矩形相对于组的位置的总和

这里,"相对位置"指的是相对于父容器(组)的位置。这个相对位置会随着父容器的移动而改变。

A相对B的绝对位置,如何通过A和B的绝对位置进行推导

要通过 A 和 B 的绝对位置推导出 A 相对于 B 的位置,可以使用以下公式:

A 相对于 B 的位置 = A 的绝对位置 - B 的绝对位置

假设 A 的绝对位置为 (Ax, Ay),B 的绝对位置为 (Bx, By),那么 A 相对于 B 的位置可以表示为:

(Ax - Bx, Ay - By)

这个结果表示 A 点在水平方向上相对于 B 点的偏移量为 Ax - Bx,在垂直方向上相对于 B 点的偏移量为 Ay - By。

举个例子,如果 A 的绝对位置为 (100, 200),B 的绝对位置为 (50, 100),那么 A 相对于 B 的位置就是:

(100 - 50, 200 - 100) = (50, 100)

这表示 A 点在水平方向上相对于 B 点的偏移量为 50,在垂直方向上相对于 B 点的偏移量为 100。

通过这个公式,你可以根据 A 和 B 的绝对位置计算出 A 相对于 B 的位置。这在计算图形元素之间的相对位置、碰撞检测等情况下非常有用。

矩形的相对位置,怎么算

矩形的相对位置是指相对于其父容器(比如一个组)的位置。对于 KonvaJS,可以通过以下步骤计算矩形的相对位置:

  1. 获取矩形的绝对位置: 使用 getAbsolutePosition() 方法获取矩形在舞台上的绝对位置,即相对于舞台的位置。

    javascript 复制代码
    var absolutePosition = rect.getAbsolutePosition();
  2. 获取父容器(组)的绝对位置: 如果矩形位于组中,可以获取组的绝对位置。

    javascript 复制代码
    var groupAbsolutePosition = group.getAbsolutePosition();
  3. 计算相对位置: 矩形相对于其父容器的位置是矩形的绝对位置减去父容器的绝对位置。

    javascript 复制代码
    var relativePosition = {
      x: absolutePosition.x - groupAbsolutePosition.x,
      y: absolutePosition.y - groupAbsolutePosition.y,
    };

现在,relativePosition 对象包含了矩形相对于其父容器的位置,即矩形的相对位置。

请注意,如果矩形直接添加到舞台而不是在组内,那么父容器的绝对位置就是 { x: 0, y: 0 },因为舞台本身就是顶层容器。在这种情况下,相对位置就等于矩形的绝对位置。

已知stage舞台上有一个图片,图片的宽高和舞台不一定一样,但需要保证在保持图片宽高比的情况下,尽可能居中占满舞台。同时,支持给图片上画标注框,最后将标注框的数据信息保存到后端服务器。再次打开图片时,根据从后端获取的标注框的信息,回显标注框。注意兼容不同的屏幕分辨率和浏览器的大小。请给出你的设计思路

设计思路如下:

  1. 初始化图片与舞台适配

    • 首先,获取舞台(Stage)的宽高。
    • 然后,加载图片资源,获取图片原始宽高。
    • 根据舞台和图片的实际尺寸,计算图片缩放比例以保持宽高比不变,并且尽可能充满舞台。可以选择以下两种方式之一: a) 按较短边等比例缩放至刚好填满舞台的相应边;若图片长边超出舞台,则居中裁剪或留白。 b) 按较长边等比例缩放至不超出舞台边界,然后居中显示。
  2. 绘制并调整图片

    • 创建一个Konva.Image对象,将图片资源设置给它,并根据计算出的比例设置其宽度和高度。
    • 设置Image的定位属性,使其在舞台上居中显示。
  3. 标注框的设计与交互

    • 当用户需要在图片上添加标注框时,监听鼠标事件,例如点击、拖拽等,创建可缩放、移动的Konva.Rect对象作为标注框,允许用户自由调整大小和位置。
    • 为每个标注框关联必要的数据信息,如坐标、尺寸、类型等。
  4. 保存标注信息到后端

    • 用户完成标注操作后,将所有标注框的位置、尺寸和相关数据序列化成JSON格式。
    • 使用Ajax或者Fetch API向后端服务器发送POST请求,将JSON数据保存到数据库。
  5. 从后端加载及回显标注信息

    • 页面加载时,向后端发起GET请求获取该图片已有的标注信息。
    • 后端返回JSON格式的标注数据,遍历数据列表,在前端按照数据重新创建对应的Konva.Rect标注框,设置好它们的位置、尺寸以及任何关联的样式和属性。
    • 将这些还原的标注框添加到图片所在的层中,确保当页面窗口大小改变时,通过监听窗口 resize 事件来更新舞台和内容布局,使得标注框能正确适应新的屏幕分辨率。
  6. 兼容性处理

    • 对于不同的屏幕分辨率和浏览器大小,需确保舞台容器具有响应式设计,可以使用CSS实现自适应布局。
    • 在JS层面,监听窗口的resize事件,每当窗口大小变化时,重新计算图片的缩放比例和居中位置,并且调整标注框的位置以匹配新的视口大小。

阻止mousemove鼠标移动或touchmove触摸移动触发click点击事件

mousedown mousemove mouseup 与 click事件冲突的解决办法 blog.csdn.net/weixin_4504... 但是canvas 里的图形貌似不生效

相关推荐
cs_dn_Jie21 分钟前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic1 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿1 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具2 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
qq_390161772 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test3 小时前
js下载excel示例demo
前端·javascript·excel
Yaml43 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事3 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶3 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo3 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx