如何在SVG中获取标记末端的位置?

3
以下是您可以运行并查看输出的代码,输出结果为一条带标记的黑色线条。

<svg width="600px" height="200px">
  <defs>
    <marker id="arrow" markerWidth="10" markerHeight="10" refx="0" refy="3" orient="auto" markerUnits="strokeWidth">
      <path d="M0,0 L0,6 L9,3 z" fill="#000" />
    </marker>
  </defs>

  <line x1="50" y1="50" x2="250" y2="150" stroke="#000" stroke-width="5" marker-end="url(#arrow)" />
</svg>

我想知道是否有可能计算出如下图片中用红色圆圈标注并由红色箭头指向的位置的标记结束位置的值enter image description here?在数学上有可能计算出标记结束位置的位置吗?

我不确定是否理解正确。您想在箭头末端添加一个红色圆圈吗?还是您希望箭头指向圆圈而不重叠?在第二种情况下,这是固定图像吗?还是有用户交互?因为如果它只是一个固定的图像,它有点进入我所说的第一种情况。那个红色圆圈来自哪里?它是固定的吗?请提供详细信息 =) - Elfayer
@Elfayer 我想知道黑色线条的结束点位置(即以标记符号(三角形)为末端位置)。请查看代码输出和图像中我用红色圆圈标记的点。 - Ashok kumar
我更新了我的回答,我终于找到了解决方案 =) - Elfayer
1个回答

7

您只需使用以下公式即可获取红色圆圈的正确位置(箭头的端点):

this.point.x = r * Math.cos(rad) + this.line.endX;
this.point.y = r * Math.sin(rad) + this.line.endY;

对于位置x的基本定义:

posX = arrowSizeX[箭头宽度 * 线条宽度] * Math.cos(rad)[rad = 线条角度(弧度)] + lineEndX[箭头起始点位置]

完整代码如下: (JSFiddle)

var vue = new Vue({
  el: '#container',
  data: {
    svg: {
      width: 400,
      height: 200
    },
    line: {
      startX: 50,
      startY: 50,
      endX: 250,
      endY: 150
    },
    point: {
      x: 0,
      y: 0
    },
    arrow: {
      sizeX: 9,
      sizeY: 6
    },
    strokeWidth: 5
  },
  ready: function() {
    this.calculatePosition();
  },
  methods: {
    calculatePosition: function() {
      // Calculate the angle of the arrow in radian
      var rad = Math.atan2(this.line.endY - this.line.startY, this.line.endX - this.line.startX);

      // Calculate the radius (the length of the arrow)
      // Note: Your arrow size depends on the the 'strokeWidth' attribute of your line
      var r = this.arrow.sizeX * this.strokeWidth;

      // Calculate the position of the point
      this.point.x = r * Math.cos(rad) + this.line.endX;
      this.point.y = r * Math.sin(rad) + this.line.endY;
    }
  }
});

vue.$watch('arrow.sizeX', vue.calculatePosition);
vue.$watch('arrow.sizeY', vue.calculatePosition);
vue.$watch('line.startX', vue.calculatePosition);
vue.$watch('line.startY', vue.calculatePosition);
vue.$watch('line.endX', vue.calculatePosition);
vue.$watch('line.endY', vue.calculatePosition);
vue.$watch('strokeWidth', vue.calculatePosition);
input,
label,
button {
  display: block;
}
#toolbar {
  display: inline-block;
  width: 150px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<div id="container">
  <div id="toolbar">
    <label>Arrow size x:</label>
    <input type="range" min="1" max="10" v-model="arrow.sizeX" v-on:change="calculatePosition()" />
    <label>Arrow size y:</label>
    <input type="range" min="1" max="10" v-model="arrow.sizeY" />
    <label>Line start x:</label>
    <input type="range" min="0" max="{{svg.width}}" v-model="line.startX" />
    <label>Line start y:</label>
    <input type="range" min="0" max="{{svg.height}}" v-model="line.startY" />
    <label>Line end x:</label>
    <input type="range" min="0" max="{{svg.width}}" v-model="line.endX" />
    <label>Line end y:</label>
    <input type="range" min="0" max="{{svg.height}}" v-model="line.endY" />
    <label>Stroke width:</label>
    <input type="range" min="1" max="10" v-model="strokeWidth" />
  </div>
  <svg width="{{svg.width}}" height="{{svg.height}}">
    <defs>
      <marker id="arrow" markerWidth="10" markerHeight="10" refx="0" refy="{{arrow.sizeY / 2}}" orient="auto" markerUnits="strokeWidth">
        <path d="M0,0 L0,{{arrow.sizeY}} L{{arrow.sizeX}},{{arrow.sizeY / 2}} z" fill="#000" />
      </marker>
    </defs>
    <circle cx="{{point.x}}" cy="{{point.y}}" r="3" fill="red"></circle>
    <line x1="{{line.startX}}" y1="{{line.startY}}" x2="{{line.endX}}" y2="{{line.endY}}" stroke="#000" stroke-width="{{strokeWidth}}" marker-end="url(#arrow)" />
  </svg>
</div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接