ashokgct - 1 year ago 167
Javascript Question

# How to get the marker-end position in svg?

Below is the code you can run and see the output which is a black coloured line with a marker at its end position.

``````<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>``````

I want to know whether its is possible to calculate the value of marker end position as shown in the image below with a circle in red color which is pointed by the arrow in red color?
Is it possible mathematically to calculate the position of marker end?

The only thing you have to do is use the following formulas to get the correct position of the red circle (so the end point of the arrow):

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

Basically for position x:

`posX = arrowSizeX[width of the arrow * line stroke width] * Math.cos(rad)[rad = angle of the line in radian] + lineEndX[Position of the starting point of the arrow]`

Full code below: (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
},
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>``````

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download