Gradio Agents & MCP 黑客松

获胜者
Gradio logo

Gradio 新手?从这里开始:入门

查看发布历史

技术说明

v0.2.6

总结

  • 我们使用 object-fit: contain 来始终显示完整图像。
  • 这导致图像的 DOM 宽度与实际图像宽度不同。
  • 滑块位置基于未缩放图像的坐标空间。
  • 缩放会引入平移和缩放,这使得滑块位置的行为出乎意料(包括变为负数)。

详情

该组件的主要挑战是管理图像尺寸。不同的方法可能会带来其他挑战,但我想在这里记录下这个方法,因为它不是特别直观。

object-fit: contain

图像滑块本质上是两个图像精确叠加;“比较”图像通过修改其 clip-path 逐渐显示。

我们有几个关键要求

  • 整个图像应可见,不被裁剪。
  • 理想情况下,图像的 DOMRect 应与其父容器的宽度和高度匹配 100%——这在缩放时至关重要,因为我们不希望图像的任何部分被裁剪。
  • 两个图像必须完全相同地叠加。

我们使用了一些标准的 CSS 技术来实现此目的,但本文讨论的关键部分是 object-fit: contain

这是一个很棒的 CSS 属性,它确保始终显示整个图像,这是图像滑块的一个很好的基础。object-fit: contain 的挑战(也是优势)在于,设置了 width: 100% 和此属性的图像会拉伸到其父容器的全部宽度,即使图像本身较窄。

这有问题,因为滑块进度应相对于未缩放图像,而不是容器框。当有人设置 slider_position=10 时,这应表示图像宽度的 10%,而不是容器宽度的 10%。

这没问题。我们手动计算“实际”图像宽度和偏移量(没有内置 API 可以做到这一点),并据此映射滑块位置值。它确实有效,但会引入一些奇怪的行为:

缩放需要知道“实际”图像尺寸。

缩放应用了限制以防止用户将图像拖出视图,因此它需要知道图像的真实起始和结束位置(即图像在容器内的实际像素边界)。

滑块位置可能变为“负数”(这没问题)。

这令人困惑,但请耐心听我解释。

在默认缩放级别下,slider = 0slider = 100 对应于图像的实际边缘。这说得通。但当我们放大时,我们仍然使用相同的“未缩放的实际图像坐标空间”。

因此,现在假设滑块在 25 的位置:它仍然指的是未缩放图像宽度的 25%。但视觉上,这可能不再与缩放视图中的预期位置对齐。它是相对于视口的,但计算是基于一个非视口的原始坐标系统。

我画了一张图来帮助理解概念。在这里,我们进行缩放(比例和平移),但滑块保持在屏幕上的同一位置,对应于其未缩放图像宽度 25% + 左侧偏移的起始点。

因此,由于这一点,在缩放时,0 点实际上可能位于图像可见区域的一部分内部。这意味着除非我们允许负的滑块位置,否则我们无法在更高的缩放级别下比较整个图像。

所以这正是我们所做的。

图像滑块执行了相当多的平移和投影,这并不荒谬,但也足够复杂了。我们需要确保在与滑块位置交互时,我们的计算可以处理负值。

我们还需要根据以下因素动态限制滑块位置:

  • 当前缩放比例
  • 任何平移偏移量
  • 实际图像边界(不仅仅是 DOMRect)