SVG.js library - could not draw a curve using draw.path - javascript

I am using SVG.js library to draw a curve in JavaScript. To do that, I used the below code
var x1 = parseInt(left_bulb[i]) + 4;
var y1 = parseInt(top_bulb[i]) + 16
var x2 = parseInt(left_bulb[i]) + 4;
var y2 = parseInt(top_bulb[i]) + 16
var x3 = parseInt(left_bulb[i]) + 16 - 1;
var y3 = parseInt(top_bulb[i]);
var x4 = parseInt(left_bulb[i]) + 16 + 4;
var y4 = parseInt(top_bulb[i]) + 16 - 1;
draw.path('M x1,y1 C x2,y2 x3,y3 x4,y4').stroke({width:3, color:"#000000"});
The below draw.path() code works fine. This function works fine when direct numbers are given but not with variables like x1, y1... so on. Could you please tell me how to get it working with the variables given. It does not give a curve for the above code.
var path = draw.path('M100,200 C100,100 400,100 400,200 H 500 V 400 Z')
.stroke({width:9, color:"#f23"})
.fill('orange')

You need to evaluate the arguments. At the moment you're just creating a string with the character x1,y1 etc in it.
var x1 = parseInt(left_bulb[i]) + 4;
var y1 = parseInt(top_bulb[i]) + 16
var x2 = parseInt(left_bulb[i]) + 4;
var y2 = parseInt(top_bulb[i]) + 16
var x3 = parseInt(left_bulb[i]) + 16 - 1;
var y3 = parseInt(top_bulb[i]);
var x4 = parseInt(left_bulb[i]) + 16 + 4;
var y4 = parseInt(top_bulb[i]) + 16 - 1;
draw.path('M ' + x1 + ',' + y1 + ' C ' + x2 + ',' + y2 + ' ' + x3 + ',' + y3 + ' ' + x4 + ',' + y4).stroke({width:3, color:"#000000"});

Related

How to draw multiple self-edges in a node-link diagram in D3

Drawing a single self-link on a node in a node-link diagram can be done as described here: D3 Force Layout Self-Linking Node
What would you change if you need to draw multiple links on the same node?
I tried to add a 'rotation' to it based on the number of self-links that exist.
Given the code from the linked example I made the following changes:
function tick() {
link.attr("d", function(d) {
var x1 = d.source.x,
y1 = d.source.y,
x2 = d.target.x,
y2 = d.target.y,
dx = x2 - x1,
dy = y2 - y1,
dr = Math.sqrt(dx * dx + dy * dy),
// Defaults for normal edge.
drx = dr,
dry = dr,
xRotation = 0, // degrees
largeArc = 0, // 1 or 0
sweep = 1; // 1 or 0
// Self edge.
if ( x1 === x2 && y1 === y2 ) {
// Fiddle with this angle to get loop oriented.
var index = getIndexOfDuplicateEdge();
var degree = 360 / numberOfDuplicateEdges();
var degreeForIndex = degree * index;
xRotation = degreeForIndex; // Previously: -45;
// Needs to be 1.
largeArc = 1;
// Change sweep to change orientation of loop.
//sweep = 0; // I also tried to change it based on index % 2
// Make drx and dry different to get an ellipse
// instead of a circle.
drx = 30;
dry = 20;
// For whatever reason the arc collapses to a point if the beginning
// and ending points of the arc are the same, so kludge it.
x2 = x2 + 1;
y2 = y2 + 1;
}
return "M" + x1 + "," + y1 + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + x2 + "," + y2;
});
This won't draw my ellipses as expected and I cannot find a way to handle this. Based on SVG from Mozilla the large-arc has to be 1. Sweep can be 0 or 1 and will 'mirror' my ellipsis. I can use xRotation between 90-180 with sweep 0/1 which will cover 180 degrees of my circle. However, i do not find a way to draw the ellipsis at the other 180 degree positions.
The number of self-links can vary, and I always want to have the 'best' distribution between ellipsis.
Ideally, it should look like:
The idea is to divide the circle into as many segments as petals your flower has. Then calculate the start- and end points for each petal on the circle and fitting an elipse on those points.
You can use the following code snippet to do achieve this: (the function assumes you have a svg element with the id "svgthing")
function radtodeg(angle) {
return angle * (180/Math.PI);
}
function flower( center_x, center_y, num_self_edges, start_angle, end_angle, radius, length ) {
var angle_sector = end_angle - start_angle;
var num_points = num_self_edges * 2;
var angle_per_point = angle_sector / num_points;
var angle_per_sector = angle_per_point * 2;
var str_builder = [];
for( var angle = start_angle; angle < end_angle; angle += angle_per_sector ) {
var start_sector_angle = angle;
var end_sector_angle = angle + angle_per_point;
var mid_sector_angle = angle + angle_per_point / 2;
var start_x = center_x + (radius * Math.cos(start_sector_angle));
var start_y = center_y + (radius * Math.sin(start_sector_angle));
var end_x = center_x + (radius * Math.cos(end_sector_angle));
var end_y = center_y + (radius * Math.sin(end_sector_angle));
var mid_x = center_x + (radius * Math.cos(mid_sector_angle));
var mid_y = center_y + (radius * Math.sin(mid_sector_angle));
str_builder.push("<path d='");
str_builder.push("M" + start_x + " " + start_y + ",");
str_builder.push("A " + length + " 1 " + radtodeg(mid_sector_angle) + " 0 1 " + end_x + " " + end_y);
str_builder.push("'/>\n");
str_builder.push("<circle cx='" + start_x + "' cy='" + start_y + "' r='5' />\n");
str_builder.push("<circle cx='" + end_x + "' cy='" + end_y + "' r='5'/>\n");
str_builder.push("<circle cx='" + mid_x + "' cy='" + mid_y + "' r='5'/>\n");
}
str_builder.push("<circle cx='" + center_x + "' cy='" + center_y + "' r='" + radius + "' />\n");
$("#svgthing").html(str_builder.join(""));
}
flower(60, 50, 8, 0, 2 * Math.PI, 50, 10);
The example call will generate a flower with 8 petals.

How to convert value of Length Seconds in PHP

This is video Length in seconds : 145
and i want to out put this value like this ,80,74,2, How can i get Length Seconds 145 to Convert like ,80,74,2, in PHP
{"length_seconds":"145"} how to i covert length_seconds 145 in this format 80,74,2
For this example JavaScript
videojs('mint').thumbnails(eval("("+mksb('G_0TziI12SE',80,74,2,'wa1cIFpwGxMNbz9bRlRFZCkjlOc')+")"));
Alright, by digging through the source code, I found mksb() in videojs.thumbnails.js:
function mksb(vid, img_width, frames, interval, sihg) {
var r = '';
counter = 0;
for (k = 0; k < 50; k++) {
for (j = 0; j < 10; j++) {
for (i = 0; i < 10; i++) {
if (counter == frames) break;
x1 = img_width * i;
x2 = x1 + 40;
x3 = x1 + 80;
y1 = j * 45;
y2 = y1 + 60;
y3 = y1 + 45;
x4 = frames - k * 100;
if (x4 < 100) {
x4 = Math.ceil(x4 / 10) * 45;
} else {
x4 = 450;
};
m = '//img.ytapi.com/sb/' + vid + '/storyboard3_L1/M' + k + '.jpg?sigh=' + sihg;
r += counter++ * interval + ":{src:'" + m + "',style:{left:'-" + x2 + "px',width:'" + img_width * 10;
r += "px',height:'" + x4 + "px',top:'-" + y2 + "px',clip:'rect(" + y1 + "px," + x3 + "px," + y3 + "px," + x1 + "px)'}},";
}
}
}
return '{' + r + '}';
}
So, 'G_0TziI12SE' is the video ID, 80 is the thumbnail width, 74 seems to be a frame count, 2 seems to be an interval in seconds, and I have no idea what 'wa1cIFpwGxMNbz9‌​bRlRFZCkjlOc' is, but perhaps a cryptographic signature?
So, 74 * 2 is 148, which is fairly close to 145, but that's as close as I can get. This basically seems to be a "frames # frame-rate" type of expression. So, to convert seconds into this type of expression, you'd just do (int) $seconds / 2.
That's all I've got, but I hope it helps point you in the right direction.

Draw regular polygons inscribed in a circle

I'm trying to draw regular polygons(square and equilateral triangle) inscribed in a circle of a given centre (x,y) and a radius (r). I'm using raphael.js.
Here's my function to draw a inscribed square:
function draw_square(x,y,radius){
var side= radius*(Math.sqrt(2));
var x = x - (side/2);
var y = y - (side/2);
var square= paper.rect(x, y, side, side);
}
Can anyone shed some light on how I could draw an equilateral triangle(inscribed in a given circle)?
First time I've used raphael, so you'll have to extract what you need from the following:
<html>
<body>
<div id="paper"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.4/raphael-min.js"></script>
<script>
var paper = new Raphael(document.getElementById('paper'), 256, 256);
var x = 128, y = 128, r = 64, n = 9;
paper.circle(x, y, r);
var xx, yy, i, a, pathString = "";
for (i = 0; i <= n; ++i) {
a = ((4 * Math.PI * i) + (Math.PI * n) + (2 * Math.PI)) / (2 * n);
xx = x + r * Math.cos(a);
yy = y + r * Math.sin(a);
pathString += (i == 0 ? "M " : " L ") + xx + " " + yy;
}
pathString += " z";
paper.path(pathString);
</script>
</body>
</html>
EDIT: Refactored to use var a, and to always have a horizontal base.
function draw_triangle(x, y, radius){
var x_offset =radius*(Math.cos(Math.PI/6));
var y_offset =radius*(Math.sin(Math.PI/6));
var x1 = x;
var y1 = y - radius;
var x2 = x + x_offset;
var y2 = y + y_offset;
var x3 = x - x_offset;
var y3 = y + y_offset;
var triangle = "M"+x1+","+y1+"L"+x2+","+y2+"L"+x3+","+y3+"Z";
var triangle= paper.path(triangle);
}
With a little help of trigo and raphael paper.path().

Raphael JS sweeping clock

Using Raphael JS I want to have a continuing sweeping clock.
I have kind of got it implemented but there is a problem.
The transform on the animation constantly requries a increasing integer to rotate. Eventually I'm going to hit a max integer.
If I use 0,90,180,270. When it hits 0 again it goes back the other way.
CodePen ->
http://codepen.io/ianw92/pen/yNLdZz
Javascript:
var svg = Raphael("container",400,400),
triangle = svg.path("M210 200L190 200L200 100Z").attr({fill:"#000"}),
circle = svg.circle(200,200,5).attr({fill:"#f00"});
// Rotation settings
var handAngle = 45,
centerX = 200,
centerY = 200;
y = 0
function a() {
y = (y + 90) % 360;
triangle.animate({transform: "r"+y + "," + centerX + "," + centerY}, 500, b);
}
function b() {
y = (y + 90) % 360;
triangle.animate({transform: "r"+y + "," + centerX + "," + centerY}, 500, a);
}
a()
Key was to use Raphael.animation(...).repeat(Infinity)
http://codepen.io/ianw92/pen/xGbKJq
var anim=Raphael.animation({transform: "r360" + "," + centerX + "," + centerY}, 60000, 'linear').repeat(Infinity);
triangle.animate(anim);

SVG donut slice as path element (annular sector)

Ok so granted, its not a bug, but I am confounded by how to get a perfect circle arc between points via Bézier curve.
I need a shape like this:
So I've been calculating the four corner points like this from the center point, radius and angle with the following formula: (x?,y?)=(x+d cos α,y+d sin α), which in my coffeescript looks something like this:
x1 = centerPointX+outerRadius*Math.cos(currentAngle)
y1 = centerPointY+outerRadius*Math.sin(currentAngle)
x2 = centerPointX+innerRadius*Math.cos(currentAngle)
y2 = centerPointY+innerRadius*Math.sin(currentAngle)
x3 = centerPointX+outerRadius*Math.cos(currentAngle2)
y3 = centerPointY+outerRadius*Math.sin(currentAngle2)
x4 = centerPointX+innerRadius*Math.cos(currentAngle2)
y4 = centerPointY+innerRadius*Math.sin(currentAngle2)
How can I take the information I have and result in a path element with perfect circular curves?
(PS I am newish to SVG and if you want to help me out with the proper syntax for d= that would be cool, but I can always just write it myself. The challenge I would like help with is really more to do with Bézier.
UPDATE / SOLUTION
Using the answer below a guidance below is the function I actually used:
annularSector = (centerX,centerY,startAngle,endAngle,innerRadius,outerRadius) ->
startAngle = degreesToRadians startAngle+180
endAngle = degreesToRadians endAngle+180
p = [
[ centerX+innerRadius*Math.cos(startAngle), centerY+innerRadius*Math.sin(startAngle) ]
[ centerX+outerRadius*Math.cos(startAngle), centerY+outerRadius*Math.sin(startAngle) ]
[ centerX+outerRadius*Math.cos(endAngle), centerY+outerRadius*Math.sin(endAngle) ]
[ centerX+innerRadius*Math.cos(endAngle), centerY+innerRadius*Math.sin(endAngle) ]
]
angleDiff = endAngle - startAngle
largeArc = (if (angleDiff % (Math.PI * 2)) > Math.PI then 1 else 0)
commands = []
commands.push "M" + p[0].join()
commands.push "L" + p[1].join()
commands.push "A" + [ outerRadius, outerRadius ].join() + " 0 " + largeArc + " 1 " + p[2].join()
commands.push "L" + p[3].join()
commands.push "A" + [ innerRadius, innerRadius ].join() + " 0 " + largeArc + " 0 " + p[0].join()
commands.push "z"
return commands.join(" ")
Demo: http://phrogz.net/svg/procedural_annular_sector.xhtml
Usage:
annularSector( myPathElement, {
centerX:100, centerY:150,
startDegrees:190, endDegrees:230,
innerRadius:75, outerRadius:100
});
Core function:
// Options:
// - centerX, centerY: coordinates for the center of the circle
// - startDegrees, endDegrees: fill between these angles, clockwise
// - innerRadius, outerRadius: distance from the center
// - thickness: distance between innerRadius and outerRadius
// You should only specify two out of three of the radii and thickness
function annularSector(path,options){
var opts = optionsWithDefaults(options);
var p = [ // points
[opts.cx + opts.r2*Math.cos(opts.startRadians),
opts.cy + opts.r2*Math.sin(opts.startRadians)],
[opts.cx + opts.r2*Math.cos(opts.closeRadians),
opts.cy + opts.r2*Math.sin(opts.closeRadians)],
[opts.cx + opts.r1*Math.cos(opts.closeRadians),
opts.cy + opts.r1*Math.sin(opts.closeRadians)],
[opts.cx + opts.r1*Math.cos(opts.startRadians),
opts.cy + opts.r1*Math.sin(opts.startRadians)],
];
var angleDiff = opts.closeRadians - opts.startRadians;
var largeArc = (angleDiff % (Math.PI*2)) > Math.PI ? 1 : 0;
var cmds = [];
cmds.push("M"+p[0].join()); // Move to P0
cmds.push("A"+[opts.r2,opts.r2,0,largeArc,1,p[1]].join()); // Arc to P1
cmds.push("L"+p[2].join()); // Line to P2
cmds.push("A"+[opts.r1,opts.r1,0,largeArc,0,p[3]].join()); // Arc to P3
cmds.push("z"); // Close path (Line to P0)
path.setAttribute('d',cmds.join(' '));
function optionsWithDefaults(o){
// Create a new object so that we don't mutate the original
var o2 = {
cx : o.centerX || 0,
cy : o.centerY || 0,
startRadians : (o.startDegrees || 0) * Math.PI/180,
closeRadians : (o.endDegrees || 0) * Math.PI/180,
};
var t = o.thickness!==undefined ? o.thickness : 100;
if (o.innerRadius!==undefined) o2.r1 = o.innerRadius;
else if (o.outerRadius!==undefined) o2.r1 = o.outerRadius - t;
else o2.r1 = 200 - t;
if (o.outerRadius!==undefined) o2.r2 = o.outerRadius;
else o2.r2 = o2.r1 + t;
if (o2.r1<0) o2.r1 = 0;
if (o2.r2<0) o2.r2 = 0;
return o2;
}
}

Categories

Resources