SVG marker on Highcharts path - svg

I want to draw arrows on my Highcharts chart and came up with this so far. Looks nice but has problems:
higher stroke-width gives a longer arrow.
rotating the arrow will require complicated calculation like here.
If I could use a SVG marker on a Highcharts path like in this SVG tutorial drawing arrows would become much easier
My code:
renderer.path(['M', 200, 0, 'L', 200, 200,'L', 225, 200,'L',200,250,'L', 175, 200,'L', 200, 200])
.attr({
'stroke-width': 5,
stroke: 'red',fill:'red'
})
.add();
renderer.path(['M', 400, 0, 'L', 400, 200,'L', 425, 200,'L',400,250,'L', 375, 200,'L', 400, 200])
.attr({
'stroke-width': 50,
stroke: 'red',fill:'red'
})
.add();

I managed to draw arrows without using SVG marker. The arrow points exactly to the right spot, regardless of the rotation. It can even take into account the radius of the start and end point.
See fiddle
function drawArrow(startX, startY, startRadius, endX, endY, endRadius, width) {
var angle = Math.PI + Math.atan((endX - startX) / (endY - startY)),
arrowLength = 3 * width,
arrowWidth = 1.5 * width,
path = [],
startArrowX,
startArrowY,
margin = 5;
if (endY >= startY) {
//correct for circle radius
startX -= ((startRadius + margin) * Math.sin(angle));
startY -= ((startRadius + margin) * Math.cos(angle));
endX += ((endRadius + margin) * Math.sin(angle));
endY += ((endRadius + margin) * Math.cos(angle));
//correct for arrow head length
endX += (arrowLength * Math.sin(angle));
endY += (arrowLength * Math.cos(angle));
//draw arrow head
path.push('M', endX, endY);
path.push(
'L',
endX - arrowWidth * Math.cos(angle),
endY + arrowWidth * Math.sin(angle));
path.push(
endX - arrowLength * Math.sin(angle),
endY - arrowLength * Math.cos(angle));
path.push(
endX + arrowWidth * Math.cos(angle),
endY - arrowWidth * Math.sin(angle), 'Z');
} else {
//correct for circle radius
startX += ((startRadius + margin) * Math.sin(angle));
startY += ((startRadius + margin) * Math.cos(angle));
endX -= ((endRadius + margin) * Math.sin(angle));
endY -= ((endRadius + margin) * Math.cos(angle));
//correct for arrow head length
endX -= (arrowLength * Math.sin(angle));
endY -= (arrowLength * Math.cos(angle));
//draw arrow head
path.push('M', endX, endY);
path.push(
'L',
endX + arrowWidth * Math.cos(angle),
endY - arrowWidth * Math.sin(angle));
path.push(
endX + arrowLength * Math.sin(angle),
endY + arrowLength * Math.cos(angle));
path.push(
endX - arrowWidth * Math.cos(angle),
endY + arrowWidth * Math.sin(angle), 'Z');
}
renderer.path(path)
.attr({
'stroke-width': 1,
stroke: '#989898',
fill: '#989898'
}).add();
renderer.path(['M', startX, startY, 'L', endX, endY])
.attr({
'stroke-width': width,
stroke: '#989898'
}).add();

Related

How to calculate coordinates of 6 point of intersection between a circle and a equilateral triangle?

I know of an equilateral triangle the center (cx,cy) and the radius (r) of a blue circle which circumscribed it.
If I draw a green circle of any radius (radius), assuming the circle is large enough to have this intersection, can I get the coordinates of the 6 intersection points (P1, P2, P3...)?
I'm looking for P5JS/processing but any other clue can help me...
Thank you in advance
Distance from the center to top point is r.
Distance from the center to the lowest triangle side is r/2 (median intersection point is center, they are divided in 1:2 ratio).
Horizontal distance from cx to p4 (and p5) is (Pythagoras' theorem)
dx = sqrt(radius^2 - r^2/4)
So coordinates of p4 and p5 are (relative to center)
p4x = dx
p4y = r/2
p5x = -dx
p5y = r/2
Other points might be calculated using rotation by 120 degrees
p2x = p4x*(-1/2) - p4y*(sqrt(3)/2)
p2y = p4x*(sqrt(3)/2) + p4y*(-1/2)
and so on.
And finally add cx,cy to get absolute coordinates
If you want to test... ;-)
function setup() {
createCanvas(500, 500);
const cx = width / 2;
const cy = height / 2;
const r = 250; // taille du triangle
const radius = 180; // externe
noFill();
strokeWeight(3);
stroke(0, 0, 0);
drawTriangle(cx, cy, r);
strokeWeight(1);
stroke(0, 0, 255);
circle(cx, cy, r * 2);
strokeWeight(2);
stroke(8, 115, 0);
circle(cx, cy, radius * 2);
noStroke();
fill(215, 0, 0);
// dx = sqrt(Math.pow(r / 2, 2) - Math.pow(r / 2, 2 / 4));
dx = sqrt(radius * radius - (r * r) / 4);
p4x = dx;
p4y = r / 2;
circle(cx + p4x, cy + p4y, 20);
text("p4", cx + p4x, cy + p4y + 30);
p5x = -dx;
p5y = r / 2;
circle(cx + p5x, cy + p5y, 20);
text("p5", cx + p5x - 10, cy + p5y + 30);
p6x = p4x * (-1 / 2) - p4y * (sqrt(3) / 2);
p6y = p4x * (sqrt(3) / 2) + p4y * (-1 / 2);
circle(cx + p6x, cy + p6y, 20);
text("p6", cx + p6x - 30, cy + p6y);
p2x = p6x * (-1 / 2) - p6y * (sqrt(3) / 2);
p2y = p6x * (sqrt(3) / 2) + p6y * (-1 / 2);
circle(cx + p2x, cy + p2y, 20);
text("p2", cx + p2x + 10, cy + p2y - 10);
p1x = p5x * (-1 / 2) - p5y * (sqrt(3) / 2);
p1y = p5x * (sqrt(3) / 2) + p5y * (-1 / 2);
circle(cx + p1x, cy + p1y, 20);
text("p1", cx + p1x - 20, cy + p1y - 10);
p3x = p1x * (-1 / 2) - p1y * (sqrt(3) / 2);
p3y = p1x * (sqrt(3) / 2) + p1y * (-1 / 2);
circle(cx + p3x, cy + p3y, 20);
text("p3", cx + p3x + 20, cy + p3y - 10);
noFill();
stroke(0, 255, 255);
triangle(cx + p2x, cx + p2y, cx + p4x, cx + p4y, cx + p6x, cx + p6y);
stroke(255, 0, 255);
// prettier-ignore
triangle(
cx + p1x, cx + p1y,
cx + p3x, cx + p3y,
cx + p5x, cx + p5y,
)
}
function drawTriangle(cx, cy, radius) {
noFill();
trianglePoints = [];
for (var i = 0; i < 3; i++) {
var x = cx + radius * cos((i * TWO_PI) / 3.0 - HALF_PI);
var y = cy + radius * sin((i * TWO_PI) / 3.0 - HALF_PI);
trianglePoints[i] = {
x,
y,
};
}
triangle(
trianglePoints[0].x,
trianglePoints[0].y,
trianglePoints[1].x,
trianglePoints[1].y,
trianglePoints[2].x,
trianglePoints[2].y
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.min.js"></script>

Clamp segment inside rectangle

I have a rectangle, and there lines that outgoing from center of it into arbitrary position outside of rectangle. I need to clamp them to rectangle edges, so endpoint will lie on rectangle. I tried using intersection algorithms and it works, but it pretty slow because it handles any kind of collisions, while I have specific conditions: start of segment is always in center of rectangle, and end of line is always outside of rectangle, maybe there some fast algorithm for this?
I assume that rectangle dimensions are width, height and rectangle center is at (0,0)
(otherwise subtract center coordinates from endx, endy variables and add them to final results)
if abs(endx) * height <= abs(endy) * width //top or bottom side
return height/2 * endx / abs(endy), sign(endy) * height/2
else //left or right side
return sign(endx) * width/2, width/2 * endy / abs(endx)
Python quick check:
from math import copysign
def rectclamp(rectcenterx, rectcentery, width, height, lineendx, lineendy):
endx = lineendx - rectcenterx
endy = lineendy - rectcentery
if abs(endx) * height <= abs(endy) * width: #at top or bottom
return (rectcenterx + height / 2 * endx / abs(endy),
rectcentery + copysign(1, endy) * height / 2)
else:
return (rectcenterx + copysign(1, endx) * width/2,
rectcentery+ width/2 * endy / abs(endx))
print(rectclamp(6, 4, 12, 8, 9, 9))
print(rectclamp(6, 4, 12, 8, 27, 10))
print(rectclamp(6, 4, 12, 8, -12, -8))
>>>
(8.4, 8.0) #top edge
(12.0, 5.714285714285714) # right edge
(0.0, 0.0) #corner

How to find all point around center point in 2D

I have center point x: 0 and y: 0.
How to get all points distance Up to 5?
My code is not perfect:
function getPoints(startX, startY, distance) {
var res = []
for (var i = 1; i < distance; i++) {
res.push({ x: startX + i, y: startY })
res.push({ x: startX - i, y: startY })
res.push({ x: startX, y: startY + i })
res.push({ x: startX, y: startY - i })
res.push({ x: startX + i, y: startY + i })
res.push({ x: startX - i, y: startY - i })
}
console.log(res)
console.log(res.length)
}
getPoints(0, 0, 3)
Pseudocode (R=5 for your case)
for dy = 0 to R
for dx = 0 to Floor(Sqrt(R*R - dy*dy))
// or dx = 0
// while dx*dx+dy*dy<=R*R do
put startX + dx, startY + dy
put startX - dx, startY + dy
put startX + dx, startY - dy
put startX - dx, startY - dy
//dx++
If you need square, code is very simple:
for y = centerY - size to centerY + size
for x = centerX - size to centerX + size
put x, y

SVG stretch with parent DIV

I am trying to make SVG responsive, so when window is re-sized, my svg will resize as well and fill parent div as it is when viewed first time.
Here is the fiddle - http://jsfiddle.net/nhe613kt/321/
HTML
<div id="myConta">
<div id="myContaList"></div>
</div>
JS
$(window).resize(OwResize);
function OwResize() {
$("#myConta").height(window.innerHeight - (window.innerHeight / 40));
}
var sideRectW = window.innerWidth / 20,
sideRectH = window.innerHeight / 20,
width = window.innerWidth - (window.innerWidth / 50),
height = window.innerHeight - (window.innerHeight / 40),
boxW = (width - sideRectW) / 4,
boxH = (height - sideRectH) / 4,
boxSize = boxW + boxH,
xPos1 = sideRectW,
xPos2 = boxW + sideRectW,
xPos3 = (boxW * 2) + sideRectW,
xPos4 = (boxW * 3) + sideRectW,
yPos1 = 0,
yPos2 = boxH,
yPos3 = boxH * 2,
yPos4 = boxH * 3;
var CreateRect = function (x, y, boxColor, boxId) {
svgContainer.append("rect")
.attr("x", x)
.attr("y", y)
.attr("id", "rectBox" + boxId)
.attr("width", boxW)
.attr("height", boxH)
.attr("fill", boxColor)
.attr("class", "hover_group")
.attr("preserveAspectRatio", "xMaxYMid meet")
.attr("viewBox", "0 0 " + $("#myConta").width() + $("#myConta").height())
.attr("onclick", "alert('haha');");
};
var CreateRectWithLength = function (x, y, w, h, boxColor) {
svgContainer.append("rect")
.attr("x", x)
.attr("y", y)
.attr("width", w)
.attr("height", h)
.attr("fill", boxColor);
};
var CreateText = function (x, y, text, textColor, size) {
svgContainer.append("text")
.attr("x", x)
.attr("y", y)
.attr("fill", textColor)
.attr("font-size", size)
.text(text);
};
var CreateText90 = function (x, y, text, textColor, size) {
svgContainer.append("text")
.attr("x", x)
.attr("y", y)
.attr("fill", textColor)
.attr("font-size", size)
.attr("transform", "rotate(-90," + x + 20 + ", " + y + ")")
.text(text);
};
var svgContainer = d3.select("#myConta")
.append("svg")
.attr("id", "myContasvg")
.attr("width", width)
.attr("height", height)
.attr("fill", "#2E2E2E")
.attr("float", "right")
.append("g");
CreateRectWithLength(0, 0, sideRectW, window.innerHeight, "Black");
CreateRectWithLength(0, height - sideRectH, width, sideRectH, "Black");
CreateText90(0, yPos3, "Sales", "white", 16);
CreateText(xPos3, height - sideRectH / 5, "Profit", "white", 16);
CreateText(sideRectW / 2, yPos1 + (boxH / 2), "3", "white", 12);
CreateText(sideRectW / 2, yPos2 + (boxH / 2), "2", "white", 12);
CreateText(sideRectW / 2, yPos3 + (boxH / 2), "1", "white", 12);
CreateText(sideRectW / 2, yPos4 + (boxH / 2), "0", "white", 12);
CreateText(xPos1 + (boxW / 2), height - sideRectH / 2, "0", "white", 12);
CreateText(xPos2 + (boxW / 2), height - sideRectH / 2, "1", "white", 12);
CreateText(xPos3 + (boxW / 2), height - sideRectH / 2, "2", "white", 12);
CreateText(xPos4 + (boxW / 2), height - sideRectH / 2, "3", "white", 12);
CreateRect(xPos1, yPos1, "#C0FC3E", 03);
CreateRect(xPos1, yPos2, "#60FC60", 02);
CreateRect(xPos1, yPos3, "#64FE2E", 01);
CreateRect(xPos1, yPos4, "#00FF00", 00);
CreateRect(xPos2, yPos1, "#F6FF33", 13);
CreateRect(xPos2, yPos2, "#AFFC3B", 12);
CreateRect(xPos2, yPos3, "#00FF00", 11);
CreateRect(xPos2, yPos4, "#64FE2E", 10);
CreateRect(xPos3, yPos1, "#FDB500", 23);
CreateRect(xPos3, yPos2, "#8DB723", 22);
CreateRect(xPos3, yPos3, "#AFFC3B", 21);
CreateRect(xPos3, yPos4, "#60FC60", 20);
CreateRect(xPos4, yPos1, "red", 33);
CreateRect(xPos4, yPos2, "#FDB500", 32);
CreateRect(xPos4, yPos3, "#F6FF33", 31);
CreateRect(xPos4, yPos4, "#C0FC3E", 30);
var rectContainer = d3.selectAll("#rectBox33");
var rectX = rectContainer.attr("x");
console.log(rectX);
Please Note
This is not exact what I am working on, but I tried to make it as close to working example as I could.
What I don't want
I want svg to resize and fill parent div automatically on window size.
I don't know if this is what you were after, but how is this?
Demo fiddle
You need to apply the viewBox and preserveAspectRatio attributes to your SVG. Also if you want the SVG to scale with its parent <div> then you should not set the width and height to fixed values. Instead leave them unset so that the default to the value "100%".

SVG - crescent shape in raphael

I have a circle with a half circle in it which I'm going to use to create a shine effect - what I'd really like to do is make it a crescent shape
Does anybody know how to make the half circle a crescent shape so it looks a bit more 3d?
This is what I have so far
http://jsfiddle.net/Hf79W/3/
var paper = Raphael("holder", 550, 550/1.5);
var rad = Math.PI / 180;
function sector(cx, cy, r, startAngle, endAngle, params) {
var x1 = cx + r * Math.cos(-startAngle * rad),
x2 = cx + r * Math.cos(-endAngle * rad),
y1 = cy + r * Math.sin(-startAngle * rad),
y2 = cy + r * Math.sin(-endAngle * rad);
return paper.path(["M", cx, cy, "L", x1, y1, "A", r, r, 0, +(endAngle - startAngle > 180), 0, x2, y2, "z"]).attr(params);
}
var circle = paper.circle(100, 100, 50).attr({"fill":"brown"});
var fifty = sector(100,100,50,0,180,{"fill":"white","opacity":"0.4"});
I have modified the main function a bit to achieve the same.
function sector(cx, cy, r, startAngle, endAngle, params) {
var x1 = cx + r * Math.cos(-startAngle * rad),
x2 = cx + r * Math.cos(-endAngle * rad),
y1 = cy + r * Math.sin(-startAngle * rad),
y2 = cy + r * Math.sin(-endAngle * rad);
return paper.path(["M", x1, y1,
"A", r, r, 0, +(endAngle - startAngle > 180), 0, x2, y2,
"A", r*1.1, r*1.1, 0, +(endAngle - startAngle > 180), 1, x1, y1,
"z"]).attr(params);
}
In drawing the second curve, reverse the sense of drawing and increase the radius a bit. Hope that helps.
I solved this by drawing the cresecent in inkscape and then saving as SVG

Resources