首页 > 解决方案 > How to make this bezier curve resemble the one in the image

问题描述

I have been trying all over and over to produce a bezier curve that would resemble this path on which eventually, the sun moves. I was guided to use SVG in producing the effect, and then add CSS to fill the hollowness of the shape after the shape has been drawn with javascript or in this case SVG.

Can someone assist on how I should eventually make the shape in code, as I tried with SVG, but no matter what, the shape do not produce the smoothness and leaves in a few bumps in the bezier line when compared to the image.

Here is the SVG. It is in development, but the idea is the bezier has the same smoothness as the curve on the image, and later be applicable to CSS effects that could be stopped and started at random moments when needed. Is such action even possible with CSS? Meaning to fill an SVG shape with such ways it is portrayed in the image.

// The smoothing ratio
const smoothing = 0.2

const points = [
  [15, 35],
  [40, 30],
  [65, 10],
  [95, 5],
  [115, 20],
  [125, 25],
]
//there should be more attributes here eventually.
const line = (pointA, pointB) => {
  const lengthX = pointB[0] - pointA[0]
  const lengthY = pointB[1] - pointA[1]
  return {
    length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),
    angle: Math.atan2(lengthY, lengthX)
  }
}

const controlPoint = (current, previous, next, reverse) => {
  const p = previous || current
  const n = next || current
  const o = line(p, n)
  const angle = o.angle + (reverse ? Math.PI : 0)
  const length = o.length * smoothing
  const x = current[0] + Math.cos(angle) * length
  const y = current[1] + Math.sin(angle) * length
  return [x, y]
}
const bezierCommand = (point, i, a) => {

  const cps = controlPoint(a[i - 1], a[i - 2], point)

  const cpe = controlPoint(point, a[i - 1], a[i + 1], true)
  return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`
}
const svgPath = (points, command) => {
  const d = points.reduce((acc, point, i, a) => i === 0
    ? `M ${point[0]},${point[1]}`
    : `${acc} ${command(point, i, a)}`
  , '')
  return `<path d="${d}" fill="none" stroke="black" />`
}

const svg = document.querySelector('.svg')

svg.innerHTML = svgPath(points, bezierCommand)
<svg viewBox="0 0 200 50" class="svg">
</svg>

标签: javascripthtmlcsssvgbezier

解决方案


推荐阅读