创建一个交互式SVG:五分之圈
#css #网络开发人员 #svg

Mads Stoumannâ!

撰写

不久前,这些漂亮的海报出现在我的一个社交供稿上的广告中:Circle Of Fifths Ad

我通常会忽略所有广告,但是这些广告立即吸引了我 - 也许是因为我曾经在高中学习音乐并在乐队中演奏,或者也许是因为我曾经从事图形设计工作,而这些只是美丽的!

马上,我想在<svg>中重新创建它们。我经常在<svg>中重新创建艺术,以提高我的技能。但是后来让我感到震惊:如果我可以通过使海报使互动,灵活和响应能力使海报变得生动起来,该怎么办?

在本教程中,我们将使用SVG,CSS和一些数学来重新创建上述海报。

跳跃:

弧和圈子

在音乐理论(以及Wikipedia的话语)中,circle of fifths是一种将12个色度宣传作为一系列完美五分之一的方式。

圆圈有三个环。外环包含装有公寓(b)或尖锐(#)的工作人员。中环包含主要的和弦,内环包含小和弦。

一个完整的圆圈为360度,因此每个色调将为30(360/12)度。

挪威开发人员Hen Lid拥有developed some useful JavaScript functions创建<svg> Circle段的developed some useful JavaScript functions。出于我们的目的,我们将使用polarToCartesiansegmentPath方法:

function polarToCartesian(x, y, r, degrees) {
  const radians = degrees * Math.PI / 180.0;
  return [x + (r * Math.cos(radians)), y + (r * Math.sin(radians))]
}
function segmentPath(x, y, r0, r1, d0, d1) {
  const arc = Math.abs(d0 - d1) > 180 ? 1 : 0
  const point = (radius, degree) =>
    polarToCartesian(x, y, radius, degree)
      .map(n => n.toPrecision(5))
      .join(',')
  return [
    `M${point(r0, d0)}`,
    `A${r0},${r0},0,${arc},1,${point(r0, d1)}`,
    `L${point(r1, d1)}`,
    `A${r1},${r1},0,${arc},0,${point(r1, d0)}`,
    'Z',
  ].join('')
} 

第一种方法用于将极坐标转换为笛卡尔坐标,第二种方法是在SVG中使用ARC创建路径。

接下来,我们将创建自己的segment方法,该方法将为每个块称为hã¥ken segmentPath方法:

function segment(index, segments, size, radius, width) {
  const center = size / 2
  const degrees = 360 / segments 
  const start = degrees * index 
  const end = (degrees * (index + 1) + 1)
  const path = segmentPath(center, center, radius, radius-width, start, end)
  return `<path d="${path}" />`
}

index是当前的细分市场(在我们的情况下之一),segments代表段的总量(在我们的情况下,12个)。 size是圆的直径(以及我们SVG的viewBox)。 radius通常是直径的一半,但是由于我们需要三个环,因此我们需要能够为每个环更换它。最后,width是ARC的高度。

让我们调用此方法12次,使用循环,为每次迭代更新index

segment(index, 12, size = 300, radius = 150, width = 150)

如果width设置为与radius相同的值,则ARC将填充圆:The Arc Filling The Circle

但是,如果我们将width更改为50,它将仅填充三分之一的圆圈(因为50是150的三分之一):Changing The Inside Width Of The Circle

让我们通过在我们的循环中多次调用我们的segment方法来添加其他圆圈:

segment(index, 12, 300, 100, 30) /* radius = 100, width = 30)
segment(index, 12, 300, 70, 30) /* radius = 70, width = 30)

现在我们有了这个几乎看起来像蜘蛛侠ð:Adding More Circles Within The Larger Circle

在我们的五分之一圈中,应将文本精确地放在线上,如上所述。但是,弧线本身不应该。

让我们使用CSS transform函数旋转弧。由于每个块是30度,我们需要将它们旋转一半的15度:

transform: rotate(-15deg);
transform-origin: 50% 50%;

这给了我们:Rotating The Arcs Within The Circle

越来越近!

现在,让我们添加员工,平底鞋和夏普。我抓住了Wikimedia Commons所需的元素,用Jake Archibald的SVGOMG清理了它们,然后我将每个元素转换为<symbol>,这样我就可以多次<use>

但是,在我们添加这些元素并填写圆圈之前,我们应该组织数据。让我们创建一个12个对象的数组,其中包含标签和平面或尖锐的数量:

{
  outer: {
    amount: 4,
    use: 'flat'
  },
  middle: {
    label: 'A<tspan baseline-shift="super">b</tspan>'
  },
  inner: {
    label: 'Fm'
  }
}, /* etc */

<tspan baseline-shift="super">怎么了?因为我们在<svg> Land中,我们可以使用<sup>。因此,对于像公寓之类的和弦,我们用baseline-shift替换<sup>

将元素围绕一个圆圈

要将一个元素放在一个圆圈中,我们需要圆的中心点,圆的半径,角度和一些数学:

function posXY(center, radius, angle) {
  return [
    center + radius * Math.cos(angle * Math.PI / 180.0), 
    center + radius * Math.sin(angle * Math.PI / 180.0)
  ]
}

现在,让所有示例结合成一个大碎片。 data是我们之前创建的对象数组:

const size = 300; /* diameter / viewBox */
const radius = size/2;
const svg =  data.map((obj, index) => {
  const angle = index * (360 / data.length);    
  const [x0, y0] = posXY(radius, 125, angle);
  const [x1, y1] = posXY(radius, 85, angle);
  const [x2, y2] = posXY(radius, 55, angle);
  return `
  <g class="cf-arcs">
    ${segment(index, data.length, size, radius, 0, 50)}
    ${segment(index, data.length, size, 100, 0, 30, obj.middle.notes)}
    ${segment(index, data.length, size, 70, 0, 30, obj.inner.notes)}
  </g>
  <g transform="translate(${x0-15}, ${y0-radius})">
    <use width="30" xlink:href="#staff"></use>
    ${Array.from(Array(obj.outer.amount).keys()).map(i => `
      <use width="2" xlink:href="#${obj.outer.use}" class="cf-${obj.outer.use}-${i+1}"></use>`
    ).join('')}
  </g>
  <text x="${x1}" y="${y1+3}" class="cf-text-middle">${obj.middle.label}</text>
  <text x="${x2}" y="${y2+2}" class="cf-text-inner">${obj.inner.label}</text>
  `
  }).join('')

fills和strokes 造型圆圈

要设置页面的background-color并集中放置圆圈。最重要的部分是我们之前创建的<path>。没有fillstroke,我们的圆圈看起来像这样:Styling The Circle With Fills And Strokes让我们添加一些简单的造型,并带有与background-color相匹配的中风:

path {
  fill: hsl(348, 60%, 10%);
  stroke: hsl(348, 60%, 52%);
}

- 虽然我们要做,所以为什么不添加hover效果:

path:hover {
  fill: hsl(348, 60%, 25%);
}

我们终于有了五分之圈!它不漂亮吗?

请参阅CodePen上的Mads Stoumann(@stoumann)的笔Circle of Fifths

定制我们的圈子的美学

现在,让我们创建尘土飞扬的蓝色版本,而当我们介绍时,让我们添加一些微妙的噪音使其看起来很复古:

请参阅CodePen上的Mads Stoumann(@stoumann)的笔Circle of Fifths – Blue Vintage

粒状的噪声滤波器是SVG filter,用作CSS背景。

结论

在本教程中,我们使用一些数学来学习如何从头开始编码SVG。将数据放在一个圆圈中并不一定要困难,并且随着trigonometric functi3biaoqian34即将到来,即将到达CSS,这将变得更加容易。

我希望您很有趣 - 希望本文启发您与SVG进行一些创意编码!如果您有兴趣使用CSS filters with SVGsanimating SVGs with CSS,请查看这些其他文章。

这是启发本教程的original poster


您的前端是否在用户的CPU感到困惑?

随着Web前端的越来越复杂,资源刺激功能从浏览器中越来越多。如果您对监视和跟踪客户端的CPU使用,内存使用量等感兴趣,则您的所有用户都有try LogRocket

LogRocket Dashboard Free Trial Banner

LogRocket就像Web应用程序的DVR一样,记录了您的Web应用程序或网站中发生的一切。您可以汇总和报告关键的前端性能指标,重播用户会话以及应用程序状态,日志网络请求并自动浮出所有错误。

,您可以汇总和报告问题。

现代化您如何调试Web应用程序的Start monitoring for free