如何使用 SVG 在 React Native 中创建以下设计?

时间:2021-05-06 07:51:29

标签: react-native svg

有谁知道如何使用 SVG 创建以下设计?我有 SVG 格式的路径图像,所以在 SVGR 中使用它,我创建了路径,现在我需要在路径上以随机顺序添加圆圈。任何线索将不胜感激。

enter image description here

编辑: 路径的SVG代码

    <Svg
      xmlns="http://www.w3.org/2000/svg"
      width={395.215}
      height={180.855}
      viewBox="0 0 395.215 180.855"
      {...props}>

      <Path
        fill="none"
        stroke="#ecece9"
        strokeWidth={15}
        d="M7.146 160.744c16.087-50.465 64.229-94.319 115.671-92.656s60.239 86.363 89.6 100.623 47.453-4.982 51.241-65.74 24.858-126.75 61.62-79.227 62.437 90.632 62.437 115.574"
      />
    </Svg>

感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

不需要任何脚本(除了创建SVG)

  • 创建带有 <circle><animateMotion> 元素
  • 以及对单个路径的运动路径引用:<mpath href="#PATH"></mpath>
  • keyTimes 定义了从 01
  • 的路径“长度”
  • keyPoints 使用 01
  • 之间的浮点值定位圆圈
  • duration 设置为 0.001s 以进行即时显示

<style>
  svg{
    height:180px;
    background:pink;
  }
</style>
<svg viewBox="0 0 400 200">
  <style>
   circle{ r:15 }
   [done]{ fill:green }
   [todo]{ fill:yellow }
  </style>
  <path id="PATH" fill="none" stroke="grey" stroke-width="15" d="M7 161c16-50 64-94 116-93s60 86 90 101s47-5 51-66s25-127 62-79s62 91 62 116"></path>
  <circle done>
    <animateMotion dur="1s" fill="freeze" keyPoints="0;.1" keyTimes="0;1" calcMode="linear"><mpath href="#PATH"></mpath></animateMotion>
  </circle>
  <circle done>
    <animateMotion dur="1s" fill="freeze" keyPoints="0;.2" keyTimes="0;1" calcMode="linear"><mpath href="#PATH"></mpath></animateMotion>
  </circle>
  <circle done>
    <animateMotion dur="1s" fill="freeze" keyPoints="0;.3" keyTimes="0;1" calcMode="linear"><mpath href="#PATH"></mpath></animateMotion>
  </circle>
  <g><circle todo></circle>
     <text text-anchor="middle" alignment-baseline="middle">04</text>
      <animateMotion dur="1s" fill="freeze" keyPoints="0;.4" keyTimes="0;1" calcMode="linear"><mpath href="#PATH"></mpath></animateMotion>
  </g>
  <g><circle todo></circle>
     <text text-anchor="middle" alignment-baseline="middle">05</text>
      <animateMotion dur="0.01s" fill="freeze" keyPoints="0;.5" keyTimes="0;1" calcMode="linear"><mpath href="#PATH"></mpath></animateMotion>
  </g>
</svg>

更新:我接触了一个本地人!网络组件:

<svg-spread-on-path duration="1" path="P">
  <style>
    svg    { width: 100%; height:180px; background: pink }
    circle { r: 15}
    [done] { fill: green }
    [todo] { fill: yellow }
  </style>
  <path id="P" fill="none" stroke="grey" stroke-width="15" d="M7 161c16-50 64-94 116-93s60 86 90 101s47-5 51-66s25-127 62-79s62 91 62 116"></path>
  <circle done />
  <circle done />
  <circle done />
  <circle done />
  <circle todo />
  <circle todo />
  <circle todo />
</svg-spread-on-path>
<script>
  customElements.define("svg-spread-on-path", class extends HTMLElement {
    constructor() {
      let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      svg.setAttribute("viewBox", "0 0 400 200");
      super().attachShadow({mode: "open"}).append(this.svg = svg);
    }
    connectedCallback() {
      setTimeout(() => {
        this.svg.innerHTML = this.innerHTML; //   svg.append(...this.children);
        let circles = [...this.svg.querySelectorAll("circle")];
        this.svg.append(...circles.map((circle, idx) => {
          let path = this.getAttribute("path");
          let duration = this.getAttribute("duration") || 1 / 100;
          let state = circle.hasAttribute("done") ? "done" : "todo";
          let label = idx;
          let keypoint = idx * 1 / (circles.length - 1);
          let group = document.createElementNS("http://www.w3.org/2000/svg", "g");
          group.innerHTML = `<circle ${state}></circle>` +
            `<text text-anchor="middle" alignment-baseline="middle">${label}</text>` +
            `<animateMotion dur="${duration}" repeatCount="1" fill="freeze" keyPoints="0;${keypoint}" keyTimes="0;1" calcMode="linear"><mpath href="#${path}"></mpath></animateMotion>`;
          circle.remove();
          group.onclick = evt => group.querySelector("animateMotion").beginElement();
          return group;
        }));
      });
    }
  });
</script>

答案 1 :(得分:1)

您可以使用这个简单的例程计算点的位置:

const getPointsAlongPath = (path, number) => {
 const length = path.getTotalLength();
 return (new Array(number)).fill(0).map((_, i) => path.getPointAtLength(length / (number - 1) * i))
};

,其中 path 是 Path 元素,number 是要沿路径放置的点数。

React 代码可能是这样的:

const PathWithPoints({path, number}) => {
  const pathRef = useRef();
  const points = getPointsAlongPath(pathRef.current, number);

  return (
    <svg>
      <path d={path} ref={pathRef} ... />
      {points.map(({x, y}) => (<circle cx={x} cy={y} r={...} fill={...} />)}
    </svg>
  )
}

const getPointsAlongPath = (path, number) => {
 const length = path.getTotalLength();
 return (new Array(number)).fill(0).map((_, i) => path.getPointAtLength(length / (number - 1) * i))
};

const svg = d3.select('svg');
const path = svg.select('path');
const points = getPointsAlongPath(path.node(), 8);
points.forEach(({x, y}) => svg.append('circle').attr('cx', x).attr('cy', y)
.attr('r', 15).style('fill', 'red'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg
      width="450"
      height="180"
      viewBox="0 0 395.215 180.855"
>
<path
        fill="none"
        stroke="#ecece9"
        stroke-width="15"
        d="M15 160.744c16.087-50.465 64.229-94.319 115.671-92.656s60.239 86.363 89.6 100.623 47.453-4.982 51.241-65.74 24.858-126.75 61.62-79.227 62.437 90.632 62.437 115.574"
      />
 </Svg>