前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >图形编辑器开发:缩放至适应画布

图形编辑器开发:缩放至适应画布

作者头像
前端西瓜哥
发布2023-08-18 13:25:34
2370
发布2023-08-18 13:25:34
举报

大家好,我是前端西瓜哥。

之前我们实现了画布缩放的功能,本文来讲讲如何让内容缩放至适应画布大小(Zoom to fit)。

我们看看效果。

文中的动图演示来自我正在开发的图形设计工具: https://github.com/F-star/suika 线上体验: https://blog.fstars.wang/app/suika/

缩放至适应画布

这里涉及了场景坐标和视图坐标的转换,引入了 zoom 和视口概念。 如果你不理解它们,请看我的这篇文章: 《图形编辑器开发:以光标为中心缩放画布

总体思路:

  1. 计算包裹住所有图形的大包围盒 bbox(AABB 包围盒,不带旋转的);
  2. 计算新的缩放比 newZoom。需要判断是基于 bbox 的宽,还是基于高进行缩放;
  3. 最后是计算 viewport.x 和 viewport.y,将内容刚好在视口的中间位置。

最重要的是 计算缩放比,是基于 bbox 的宽还是高,去和视口宽或高相除

这个属于是 填充策略中的 contain 策略

更多填充策略,看我的这篇文章: 《在容器内显示图片的五种方案:contain、cover、fill、none、scale-down

我们需要比较 bbox 的宽高比和视口 viewport 的宽高比。

代码语言:javascript
复制
const viewportRatio = vw / vh;
const bboxRatio = bbox.width / bbox.height;
if (viewportRatio > bboxRatio) {
  // 基于 bbox 的高进行缩放
  newZoom = vh / bbox.height;
} else {
  // 基于宽
  newZoom = vw / bbox.width;
}

然后就是 小矩形在大矩形下垂直水平居中 的简单算法。下面是通过小矩形反推大矩形的位置。

代码语言:javascript
复制
 const newViewportX =
    composedBBox.x - (viewport.width / newZoom - composedBBox.width) / 2;

  const newViewportY =
    composedBBox.y - (viewport.height / newZoom - composedBBox.height) / 2;

这个算法可以看我写的文章: 《图形编辑器:绘制图形需要用到的填充算法

完整代码:

代码语言:javascript
复制
function zoomToFix() {
  //(1)计算所有图形的大包围盒
  const bbox = getRectsBBox(graphs.map((item) => item.getBBox()));

  //(2)计算 newZoom
  const vh = viewport.height; // 这里可以加个边距
  const vw = viewport.width;
  const viewportRatio = vw / vh;
  const bboxRatio = bbox.width / bbox.height;
  if (viewportRatio > bboxRatio) {
    // basic height scale
    newZoom = vh / bbox.height;
  } else {
    newZoom = vw / bbox.width;
  }

  //(3)计算视口 x 和 y 值
  const newViewportX =
    composedBBox.x - (viewport.width / newZoom - composedBBox.width) / 2;
  const newViewportY =
    composedBBox.y - (viewport.height / newZoom - composedBBox.height) / 2;

  //(4)更新视口对象
  this.setZoom(newZoom);
  this.setViewport({
    x: newViewportX,
    y: newViewportY,
  });
}

加上边距

有时候我们希望给一个边距,就像下面动图一样。

加了 50px 的边距,这样内容就不再紧贴视口边缘了,选中图形图像的控制点不至于跑到视口外。

思路是,计算 newZoom 时用的 vw 和 vh,在原来的基础减去 padding,再去计算。

需要注意的是,后面计算居中时,还是要要用原来的 viewport.x 和 viewport.y。

计算缩放比,对象是减去 padding 的视口宽高;计算位置,对象是原来的视口宽高

代码实现,改一下上面代码的第二步即可。

代码语言:javascript
复制
//(2)计算 newZoom
const padding = 50;
const vh = viewport.height - padding * 2; // 注意考虑 vh 或 vw 是负数的情况
const vw = viewport.width - padding * 2;

选中的图形适应画布

同前面的让所有图形适应画布,bbox 换成选中的图形即可。

代码语言:javascript
复制
const bbox = getRectsBBox(selectGraphs.map((item) => item.getBBox()));

结尾

缩放的大多数功能,本质就是计算新的 zoom 和视口 x,y。

基本上都逃不出 contain 填充策略,和居中对齐算法,把它们弄懂了,缩放功能基本就没啥问题了。

我是前端西瓜哥,欢迎关注我,学习开发一个图形设计工具。

相关阅读,

图形编辑器开发:以光标为中心缩放画布

图形编辑器:场景坐标、视口坐标以及它们之间的转换

图形编辑器开发:最基础但却复杂的选择工具

图形编辑器:工具管理和切换

图形编辑器:底层设计

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-06-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端西瓜哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 缩放至适应画布
  • 加上边距
  • 选中的图形适应画布
  • 结尾
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档