reactjs 使SVG文档响应基于纵横比的视图框

lx0bsm1f  于 2023-02-22  发布在  React
关注(0)|答案(1)|浏览(113)

我创建了this codesandbox来说明这个问题。
我有这个ResponsiveSVG组件:

export function ResponsiveSVG({
  height,
  width,
  children,
  origin = { x: 0, y: 0 },
  preserveAspectRatio = "xMidYMid meet",
  innerRef,
  className,
  ...props
}: ResponsiveSVGProps): JSX.Element {
  const aspect = height === 0 ? 1 : width / height;

  const adjustedHeight = Math.ceil(width / aspect);

  return (
    <div
      data-testid="cutting-svg-container"
      style={{
        position: 'relative',
        overflow: 'visible',
        height: '1px',
      }}
    >
      <svg
        style={{ overflow: 'visible' }}
        className={className}
        preserveAspectRatio={preserveAspectRatio}
        width={width}
        height={adjustedHeight}
        viewBox={`${origin.x} ${origin.y} ${width} ${height}`}
        ref={innerRef}
        {...props}
      >
        {children}
      </svg>
    </div>
  );
}

我希望我的ResponsiveSVG组件知道如何使其内容适合容器的整个宽度,同时保持纵横比不变。
在这个例子中,我有一个circle作为svg文档的子文档:

<ResponsiveSVG width={width} height={height}>
  <circle cx={width / 2} cy={height / 2} r={radius} />
</ResponsiveSVG>

在桌面上,它看起来像这样:

但在移动的视图中,它看起来是这样的:

我的计算使viewBox的宽度和高度与传入的实际宽度和高度相同,因此没有发生任何变化。
viewBox坐标与视口完全相同。

fbcarpbf

fbcarpbf1#

将包含元素的宽度和高度传递给viewBox实际上是错误的方向。viewBox定义了在其上绘制svg内容元素的画布:如果你用r="50"画一个圆,视图框宽度值必须至少为100,否则,它将无法适合。如果中心在cx=50,视图框x值必须不大于0,否则左边将被截断。
SVG中的响应性是可以实现的,因为viewBox值与<svg>元素的widthheight之间不需要有任何关系,绘制子元素的画布总是适合父元素的尺寸。
简而言之,如果你想在<svg>元素中拟合一个圆,选择一个任意半径r,设置cx=cy=rviewBox="0 0 2r 2r",它就会工作,不需要知道任何关于父元素大小的显式信息。
如果希望<svg>元素为容器的宽度,请将其设置为:width: 100%。默认高度为auto,所以不需要写它或preserveAspectRatio。它会调整自己的大小,使viewBox定义的画布适合自己。

<div
      style="
        position: relative;
        overflow: visible;
        height: 1px;
      "
    >
      <svg
        style="
          width: 100%;
          overflow: visible;
        "
        viewBox="0 0 100 100"
      >
        <circle cx="50" cy="50" r="50" />
      </svg>
    </div>

相关问题