首页 > 解决方案 > SVG 在 Safari 上的绘制方式不同

问题描述

我在 Vue 中创建了一个使用 SVG 的圆形进度条组件。其中一项要求是在进度条的尖端放置一个图标。这在 Firefox/Chrome 中正确呈现:

进度环 Firefox/Chrome

但在 Safari 中渲染时会稍微偏离:

在此处输入图像描述

下面是我用来渲染这个进度圈的代码:

<template>
  <svg
    xmlns="http://www.w3.org/2000/svg"
    :width="size"
    :height="size"
    viewBox="0 0 40 40"
    class="progress"
  >
    <defs>
      <filter id="progress-dropshadow">
        <feGaussianBlur in="SourceAlpha" stdDeviation="0.1" />
        <feOffset dx="0" dy="0.2" result="offsetblur" />
        <feComponentTransfer>
          <feFuncA type="linear" slope="0.5" />
        </feComponentTransfer>
        <feMerge>
          <feMergeNode />
          <feMergeNode in="SourceGraphic" />
        </feMerge>
      </filter>
    </defs>
    <circle cx="20" cy="20" r="18" class="progress__center" />
    <circle
      class="progress__ring"
      cx="20"
      cy="20"
      r="18"
      stroke-width="3"
      style="filter: url(#progress-dropshadow);"
    />
    <circle
      class="progress__segment"
      cx="20"
      cy="20"
      r="18"
      stroke-width="3"
      :stroke-dasharray="strokeDashArray"
      stroke-linecap="round"
    />
    <svg
      v-bind="iconCoordinates"
      class="progress-icon"
      width="4"
      height="4"
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 24 24"
    >
      <path d="M0 0h24v24H0V0z" fill="none" />
      <circle cx="15.5" cy="9.5" r="1.5" />
      <circle cx="8.5" cy="9.5" r="1.5" />
      <circle cx="15.5" cy="9.5" r="1.5" />
      <circle cx="8.5" cy="9.5" r="1.5" />
      <path
        d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm0-2.5c2.33 0 4.32-1.45 5.12-3.5h-1.67c-.69 1.19-1.97 2-3.45 2s-2.75-.81-3.45-2H6.88c.8 2.05 2.79 3.5 5.12 3.5z"
      />
    </svg>
  </svg>
</template>

<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';

const degreeToRadian = (radian: number) => (radian * Math.PI) / 180;

@Component({})
export default class PieChart extends Vue {
  @Prop({ default: 4 }) readonly value!: number;
  @Prop({ default: 236 }) readonly size!: number;
  @Prop({ default: 5 }) readonly total!: number;

  RADIUS = 18;
  circumference = 2 * Math.PI * this.RADIUS;

  get progress() {
    if (this.total === 0) return 0;
    return (this.value / this.total) * 100;
  }

  get strokeDashArray() {
    return `${(this.progress * this.circumference) / 100} ${
      this.circumference
    }`;
  }

  get iconCoordinates() {
    const scaleToDegrees = (this.progress / 100) * 360 - 90;
    const radians = degreeToRadian(scaleToDegrees);
    const xStart = Math.cos(radians) * this.RADIUS + this.RADIUS;
    const yStart = Math.sin(radians) * this.RADIUS + this.RADIUS;
    return {
      x: xStart,
      y: yStart,
    };
  }
}
</script>

<style lang="scss" scoped>
.progress__center {
  fill: transparent;
}

.progress__ring {
  stroke: $chart-ring;
  fill: transparent;
}

.progress__segment {
  fill: transparent;
  transform-origin: center;
  transform: rotate(-90deg);
  stroke: red;
}
</style>

似乎进度越远,从边缘绘制的图标就越大。

标签: vue.jssvg

解决方案


推荐阅读