Find intersect line with circle is not working in Javascript - javascript

I followed the formula to find intersect line with circle. But it does not work. Here is my code.
<svg height="397" width="851">
<circle cx="334.4" cy="198.5" r="150.8" stroke="black" stroke-width="3" fill="red" />
<line x1="485.60978255954285" y1="231.75390342766823" x2="488.9584783979701" y2="231.75390342766823" style="stroke:rgb(255,0,0);stroke-width:2" />
Sorry, your browser does not support inline SVG.
</svg>
<script>
var line1point= {x: 485.60978255954285, y: 231.75390342766823};
var line2point= {x: 488.9584783979701, y: 231.75390342766823};
var center = {x: 334.4, y: 198.5};
var intersect = inCircle(line1point, line2point, center, 150.8);
alert(intersect);
function inCircle (line1point, line2point, center, r){
var l1 = line1point, l2 = line2point, c = center;
return (Math.abs((l2.x - l1.x) * c.x + c.y * (l1.y - l2.y) + (l1.x - l2.x) * l1.y + (l1.y - l2.y) * c.y)
/ Math.sqrt(((l2.x - l1.x) * (l2.x - l1.x)) + ((l1.y - l2.y) *(l1.y - l2.y))) <= r);
}
</script>
Fiddle Link
I tried the formula given in this forum second answer. Stackexchange link

Related

How to svg morph in ReactJs between two elements

I currently have two variables defining svg elements.
I am having trouble morphing between the two, I tried react-svg-morph but the circle would disappear on each render.
What is the best way to render a morph?
This is my setup:
let hexagonShape = <svg width="100%" height="100%" viewBox="0 0 15 15" fill="green" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 4.5V10.5L7.5 14L13.5 10.5V4.5L7.5 1L1.5 4.5Z" stroke="green" strokeWidth=".6" />
</svg>
let circleShape = <svg height="100%" width="100%" viewBox="0 0 15 15" fill='blue' xmlns="http://www.w3.org/2000/svg">
<circle cy="50%" cx="50%" r="49%" stroke="blue" strokeWidth=".3" />
</svg>
const [updatedSvg, setUpdatedSvg] = useState(0)
const [updatedCircleSvg, setUpdatedCircleSvg] = useState()
const [updatedHexagonSvg, setUpdatedHexagonSvg] = useState()
function changeSvg() {
if (updatedSvg === 0) {
setUpdatedCircleSvg(true)
setUpdatedHexagonSvg(false)
}
if (updatedSvg === 1) {
setUpdatedCircleSvg(false)
setUpdatedHexagonSvg(true)
}
}
useEffect(() => {
changeSvg()
}, [updatedSvg])
And I have two simple buttons that toggle between the two svg renders:
<div className={classes.container}>
<div className={classes.shape}>
{/* this is where the svgs are being rendered */}
{updatedCircleSvg && circleShape }
{updatedHexagonSvg && hexagonShape}
</div>
<button onClick={() => setUpdatedSvg(0)}>circle</button>
<button onClick={() => setUpdatedSvg(1)}>hexagon</button>
</div>
A bit of direction would greatly help. Thank you
Here is a simple example using Quadratic Bezier curves:
const getPoints = radius => {
const factor = Math.sqrt(3);
return [
{x: 0, y: -radius},
{x: radius / factor, y: -radius},
{x: radius * factor / 2, y: -radius / 2},
{x: radius * 2 / factor, y: 0},
{x: radius * factor / 2, y: radius / 2},
{x: radius / factor, y: radius},
{x: 0, y: radius},
{x: -radius / factor, y: radius},
{x: -radius * factor / 2, y: radius / 2},
{x: -radius * 2 / factor, y: 0},
{x: -radius * factor / 2, y: -radius / 2},
{x: -radius / factor, y: -radius}
];
}
const getRoundPath = radius => {
const p = getPoints(radius);
return `M ${p[0].x},${p[0].y}
Q ${p[1].x},${p[1].y} ${p[2].x},${p[2].y}
Q ${p[3].x},${p[3].y} ${p[4].x},${p[4].y}
Q ${p[5].x},${p[5].y} ${p[6].x},${p[6].y}
Q ${p[7].x},${p[7].y} ${p[8].x},${p[8].y}
Q ${p[9].x},${p[9].y} ${p[10].x},${p[10].y}
Q ${p[11].x},${p[11].y} ${p[0].x},${p[0].y}`
};
const getHexagonPath = radius => {
const p = getPoints(radius);
for (let index = 1; index < 12; index += 2) {
const prev = p[index - 1];
const next = p[(index + 1) % 12];
p[index].x = (prev.x + next.x) / 2;
p[index].y = (prev.y + next.y) / 2;
}
return `M ${p[0].x},${p[0].y}
Q ${p[1].x},${p[1].y} ${p[2].x},${p[2].y}
Q ${p[3].x},${p[3].y} ${p[4].x},${p[4].y}
Q ${p[5].x},${p[5].y} ${p[6].x},${p[6].y}
Q ${p[7].x},${p[7].y} ${p[8].x},${p[8].y}
Q ${p[9].x},${p[9].y} ${p[10].x},${p[10].y}
Q ${p[11].x},${p[11].y} ${p[0].x},${p[0].y}`
}
const morphPath = (toHex) => {
const path = toHex ? getHexagonPath(80) : getRoundPath(80);
d3.select('path')
.transition()
.duration(750)
.attr('d', path);
setTimeout(() => morphPath(!toHex), 1000);
};
d3.select('path').attr('d', getRoundPath(80))
morphPath(true);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="200" height="200">
<g transform="translate(100,100)">
<path />
</g>
</svg>

Creating an SVG circle relative to a path in Javascript [duplicate]

This question already has answers here:
jquery's append not working with svg element?
(17 answers)
Closed 1 year ago.
How do you create a circle at the centerpoint of a filled path, in an SVG canvas, from generic Javascript or jQuery?
I've tried:
var path = $('#path123')[0];
var bb = path.getBBox();
var cx = bb.x + bb.width/2;
var cy = bb.y + bb.height/2;
$('svg').append('<circle cx="'+cx+'" cy="'+cy+'" r="40" stroke="black" stroke-width="3" fill="red" />');
but this doesn't seem to do anything, as I can't see any circle created.
You cannot manipulate an svg with code directly. You need to create a new node and insert it:
var pth = $('#path123')[0];
var bb = pth.getBBox();
var cx = bb.x + bb.width/2;
var cy = bb.y + bb.height/2;
let c = document.createElementNS('http://www.w3.org/2000/svg','circle');
c.setAttribute('cx', cx);
c.setAttribute('cy', cy);
c.setAttribute('r', 40);
c.setAttribute('fill', "red");
c.setAttribute('stroke', 'black');
c.setAttribute('stroke-width', 3);
$('svg')[0].insertBefore(c, pth);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg width="300" height="300">
<path id="path123" d="M 100 100 l 50 50 l -50 0 Z" />
</svg>
Jquery add the element on DOM but not on screen:
$(document).ready(function() {
var path = $('#path123')[0];
var bb = path.getBBox();
var cx = bb.x + bb.width / 2;
var cy = bb.y + bb.height / 2;
var obj = document.createElementNS("http://www.w3.org/2000/svg", "circle");
obj.setAttributeNS(null, "cx", cx);
obj.setAttributeNS(null, "cy", cy);
obj.setAttributeNS(null, "r", 40);
obj.setAttributeNS(null, "stroke", "black");
obj.setAttributeNS(null, "stroke-width", 3);
obj.setAttributeNS(null, "fill", "red");
$("svg")[0].append(obj,pth);
});
Another technich is to include the svg inside div for example and refresh it after appending svg:
<div id="divsvg"
<svg width="300" height="300">
<path id="path123" d="........." />
</svg>
</div>
$("svg").append('<circle ....... fill="red"/>');
$("#divsvg").html($("#divsvg").html());

How to apply rotation to graphic elements and get new path data?

How do you apply path rotation to graphic elements such as a rectangle or a path?
For example, applying rotation to a path:
<svg width="200px" height="200px" viewbox="0 0 200 200">
<rect x="100" y="0" width="20" height="20" fill="red" transform="rotate(45)"/>
</svg>
IMPORTANT NOTE:
I'm not running an browser. I remember seeing solutions that use browser or canvas to do the calculations.
I only have the markup. For a path I have the path data, for a rectangle the position and width and height, and the line the x1 y1 and x2 y2 data.
UPDATE:
It's important to know the transform origin. That would be rotated from the element center.
I would use an array of points to draw the path. For the rotation I would rotate the points and draw the rotated shape.Please read the comments in my code. I hope this is what you were asking.
const SVG_NS = svg.namespaceURI;
// the rotation
let angle = Math.PI/4;
// the points used to rotate the initial rect
let theRect = [
{ x: 100, y: 0 },
{ x: 100 + 20, y: 0 },
{ x: 100 + 20, y: 0 + 20 },
{ x: 100, y: 0 + 20 }
];
// calculating the rotated points
let rotatedRect = [];
theRect.forEach(p => {
rotatedRect.push(rotatePoint(p, angle));
});
drawRect(theRect);
drawRect(rotatedRect);
// a function to draw the rect. For this I'm using the points array
function drawRect(ry) {
let d = `M${ry[0].x},${ry[0].y}L${ry[1].x},${ry[1].y} ${ry[2].x},${ry[2].y} ${
ry[3].x
},${ry[3].y}`;
drawSVGelmt({ d: d }, "path", svg);
}
// a function used to rotate a point around the origin {0,0}
function rotatePoint(p, rot) {
let cos = Math.cos(rot);
let sin = Math.sin(rot);
return {
x: p.x * cos - p.y * sin,
y: p.x * sin + p.y * cos
};
}
// a function to draw an svg element
function drawSVGelmt(o, tag, parent) {
let elmt = document.createElementNS(SVG_NS, tag);
for (let name in o) {
if (o.hasOwnProperty(name)) {
elmt.setAttributeNS(null, name, o[name]);
}
}
parent.appendChild(elmt);
return elmt;
}
svg{border:1px solid; max-width:90vh;}
<svg id="svg" viewbox="0 0 200 200">
<rect x="100" y="0" width="20" height="20" fill="red" transform="rotate(45)"/>
</svg>

Animate svg elements with Javascript and JQuery

I'm trying to animate the following html elements to implement a functionality similar to a volume wheel.
<svg id="circle_svg" width="200" height="175">
<circle cx="100" cy="85" r="75" stroke="black" stroke-width="2" fill="lightgray"/>
<line id="line_alpha" x1="100" y1="85" x2="100" y2="160" style="stroke:rgb(0,0,255);stroke-width:2"/>
<circle id="dot_alpha" cx="100" cy="160" r="10" stroke="black" stroke-width="2" fill="red"/>
</svg>
The basic idea is that clicking on the red dot and moving the mouse around should result in the following behavior:
The red dot moves along the circle (even if mouse doesn't stay exactly on it).
The end point of the line on the circle follows the red dot.
A number shown somewhere else in the page gets incremented or decremented with the amount of angular displacement.
I found a demo online that allows to drag an svg circle all around the page, by binding the elements of interest to mousedown and mouseup events and rewriting the attribute cx and cy of the circle to the current location of the mouse.
However when testing the code on jsfiddle with my example (or even with the original code) something is not working. Could you please take a look and give me advice on what might be going wrong?
Jsfiddle my settings
Jsfiddle original settings
I was able to find the solution to my question (thanks to a friend) and will post it as reference for others:
The main problem with pasting the code from this online demo into jsfiddle is that the order in which JavaScript libraries and functions is not predictable.
So some binding might be called before the binded function is defined.
Also, the code from the demo is more complicated that what I needed.
Here is the code solution on jsfiddle
Below is a working snippet for SO site
var dragging = false
var updateGraphics = function (e) {
if (dragging) {
var parentOffset = $('#wheel').offset();
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
var cx = +$('#circle').attr('cx')
var cy = +$('#circle').attr('cy')
var r = +$('#circle').attr('r')
var dx = relX - cx
var dy = relY - cy
//var dx = e.clientX - cx
//var dy = e.clientY - cy
console.debug('cx: ' + cx);
console.debug('cy: ' + cy);
console.debug('dx: ' + dx);
console.debug('dy: ' + dy);
console.debug('clientX: ' + e.clientX);
console.debug('clientY: ' + e.clientY);
console.debug('relX: ' + relX);
console.debug('relY: ' + relY);
var a = Math.atan2(dy, dx)
var dotX = cx + r * Math.cos(a)
var dotY = cy + r * Math.sin(a)
$('#dot').attr('cx', dotX);
$('#dot').attr('cy', dotY);
$('#line_2').attr('x2', dotX);
$('#line_2').attr('y2', dotY);
}
}
$('svg').on('mousedown', function (e) {
dragging = true
updateGraphics(e)
})
$('svg').on('mouseup', function (e) {
dragging = false
})
$('svg').on('mousemove', updateGraphics)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg id="wheel" width="200" height="175" style="background-color:lightgreen;">
<circle id="circle" cx="100" cy="85" r="75" stroke="black" stroke-width="2" fill="lightgray"/>
<line id="line_1" x1="100" y1="85" x2="100" y2="160" stroke-dasharray="15,15" style="stroke:rgb(255,0,0);stroke-width:2"/>
<line id="line_2" x1="100" y1="85" x2="100" y2="160" style="stroke:rgb(0,0,255);stroke-width:2"/>
<circle id="dot" cx="100" cy="160" r="10" stroke="black" stroke-width="2" fill="red"/>
</svg>

Calculate multiple circle fragment rotations

So I have 4 SVG circles, which I'm using stroke-dash to mask. And the general idea is that they're supposed to make up one full circle based on their percentage.
I've gotten the length of each segment, and when I rotate them manually I see that it all adds up. But I can't figure out how to calculate the rotation of each segment. Under is a jsbin link to show how far I've gotten:
http://jsbin.com/lutodomujo/1/
Also, if there is better way to solve this, I'd be happy to hear it. The only thing that has to work is the hover effect as shown in the example.
By the way, the following line is a purely wild guess (as you may have noticed):
var rotate = (Math.sin((c-prevRotate)/100) * Math.PI)*100; // ?
And it is, as far as I know, the only one I need help to figure out.
var prevRotate = 0;
$('circle').each(function (i) {
var r = $(this).attr('r');
var val = $(this).data('perc');
var c = Math.PI * (r * 2);
var pct = ((100 - val) / 100) * c;
var rotate = (Math.sin((c-prevRotate)/100) * Math.PI)*100;
$(this).css({
strokeDasharray: c,
strokeDashoffset: pct,
transform: 'rotate(' + rotate + 'deg)'
});
prevRotate += pct;
});
svg { width: 300px; }
circle {
stroke-width: 3;
transform-origin: center;
}
circle:hover {stroke-width: 5}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 164 164">
<circle fill="none" stroke="#A5D2C6" cx="82" cy="82" r="80" data-perc="40"/>
<circle fill="none" stroke="#000000" cx="82" cy="82" r="80" data-perc="30"/>
<circle fill="none" stroke="#EBE6B7" cx="82" cy="82" r="80" data-perc="20"/>
<circle fill="none" stroke="#F1AAA6" cx="82" cy="82" r="80" data-perc="10"/>
</svg>
I made some change and it s work :
var prevRotate = 0;
$('circle').each(function (i) {
var r = $(this).attr('r');
var val = $(this).data('perc');
var c = Math.PI * (r * 2);
var pct = ((100 - val) / 100) * c;
var rotate = prevRotate;
$(this).css({
strokeDasharray: c,
strokeDashoffset: pct,
transform: 'rotate(' + rotate + 'deg)'
});
prevRotate += (360*val/100);
});

Categories

Resources