I am a newbie to Raphael lib, my question is following:
can I use path specific methods (like getTotalLength() or getPointAtLength()) for a circle element - this would be quite helpfull (and at the begining I thought that circle somehow inherits from path - so that should be possible... but it simply does not work :( ), ie.
var cir = paper.circle(100, 100, 20);
var totalength=cir.getTotalLength();
paper.text(50,150,'Length=('+totalength+')',20);
var pt = cir.getPointAtLength(0);
paper.text(50,250,'Point=('+pt.x+','+pt.y+')',20);
thanks for any comments/hints/explanations on that,
Borys
Sadly you cannot. Circle is its own svg element. It wouldn't be too hard to write some functions that replicate these path-specific actions:
getTotalLength:
2*pi*radius
getPointAtLength:
You'd have to figure out where the circle's path 'starts', but with that set it's something like:
rad = (length / total_length) * 2*pi
y = center_y + (sin(rad) * radius)
x = center_x + (cos(rad) * radius)
Related
I am trying to figure out a nice way to make a sine wave flow naturally along a javascript path. I made something like this:
Which captures some of the intent but it's very forced and unnatural, especially around the change direction. I also would love to accommodate for higher slope, but not sure if that ives a more natural effect or not.
Any thoughts on how I might be able to accomplish this?
The intent was:
1) Take a set of points
2) Break into equal segments
3) Adjust the actual line's position by the difference of the sin coords and the actual line coords.
This gives a pretty weak display though, and I'd like to create something that was more natural and flowing as if to capture the flow of a sine wave travelling along a path.
var c = document.getElementById("c");
var ctx = c.getContext("2d");
var cw = c.width = window.innerWidth;
var ch = c.height = window.innerHeight;
var cx = cw / 2,
cy = ch / 2;
var rad = Math.PI / 180;
var w = cw;
var h = ch * 0.3;
var amplitude = h;
var frequency = 0.01;
var phi = 0;
var frames = 0;
var stopped = true;
ctx.lineWidth = .4;
var offset = 100;
var points = interpolateLineRange( [ [0, 0], [ 95, 58], [84, 158], [350, 300], [540, 190] ], 20);
points = interpolateLineRange(points, 100);
ctx.moveTo(0, 0);
var distance_traveled = 0;
var current_slope = 0;
for (var ii in points) {
if (ii == 0) {
continue;
}
distance_traveled += dist(points[ii - 1], points[ii]);
current_slope = slope(points[ii - 1], points[ii]);
var newY = Math.sin(distance_traveled * .07) * 45 + points[ii][1];
var diff = newY - points[ii][1];
if (points[ii][1] > points[ii - 1][1]) {
ctx.lineTo(points[ii][0] - diff, newY);
} else {
ctx.lineTo(points[ii][0] + diff, newY);
}
}
ctx.stroke();
ctx.moveTo(0, 0);
for (var ii in points) {
ctx.lineTo(points[ii][0], points[ii][1]);
}
ctx.strokeStyle = 'red';
ctx.stroke();
The problem isn't really "drawing sine waves along a path": that part is actually trivial. Take your path section, express it in terms of a distance or time variable, and then draw the sines (or anything else) as an offset function:
for t=0; t<distance; t+=fraction of distance:
point = path.get(t)
normal = path.normal(t)
strength = sin(t)
if t=0:
ctx.moveTo(point + strength * normal)
else:
ctx.lineTo(point + strength * normal)
Easy enough, let's implement that: http://jsbin.com/nefemazovo/edit?js,output
Sure, it's a bit of code, but it's hardly complicated: just a class that models a polygonal path that tracks its length as we add points to it, and a draw function that draws the polygon, as well as some offset function, by sampling the polygon at regular intervals and computing the normal at each point.
The real question is: how are you going to deal with overlaps in your offset data? For instance, from the example above:
There's a pretty obvious area here where we're going to have to do ... something:
So what do we do? Turns out: no one knows, that's really up to you. For instance, you could draw "uneven" sines so that you always end up with a node at the end points of your polygonal sections. Might work, but you might also still have overlap if there's a small enough angle between consecutive segments. Plus your sines would be uneven, so would that look good? Ehh... up to you. Or, you could dampen the offset strength to zero at the polygon transition, and then ramp it back up to 100%, but will that look good? No idea, that is your call. You could also use interpolation so that the sine waves "blend" at the transition. Will that look good? Again, no idea, still up to you. You could even replace the offending section of polygon with something like a quadratic or cubic curve, so you always have smooth transitions along which sine offsets will "just work", but will that look good? ...you get the idea =)
The part of this question we can answer isn't super interesting, and the part that's interesting we unfortunately cannot answer for you...
We can give advice, though: I don't know what your polygon represents, but "curves" almost always work better as spines (almost, because curves can have discontinuities as well, which is the very thing you want to avoid), so if you can construct curves instead, probably worth it. However, that won't solve the problem of weird overlaps when your angles are too small:
You're still left with problems that can only be solved with "executive decisions" more than textbook "in this situation, do this: ..." solutions.
i want to implement the barrel shader for the oculus rift in javascript.
according to this video (http://youtu.be/B7qrgrrHry0?t=11m26s) the radius function for barrel distortion is:
newr = 0.24*r^4+0.22*r^2+1
The result:
Reference Image: After Shader:
if i change the function to newr = r i get the orginal image.
If I set the function to: newr = 0.022*r^2 i get:
This one is close but not the right solution (tested with oculus)
So its not the fault of the programm...the radius function is the problem.
Here you can try it in a fiddle: http://jsfiddle.net/s175ozts/2/
Why does the orginal function not work??
thanks :)
After trying a lot of stuff... i finally got the solution.
The trick was to normalize r first and then multiply the barrelfunction with orginal r
var sf = pr / rMax; //Scaling factor
var newR = pr*(0.24*Math.pow(sf,4)+0.22*Math.pow(sf,2)+1); //barrel distortion function
See fiddle here: http://jsfiddle.net/s175ozts/4/
Result:
Cracker0dks#: I was playing a little bit with your fiddle, and optimized it significantly:
http://jsfiddle.net/mqau9ytv/2/
/*int*/ var x_off = xmid-x;
/*int*/ var y_off = ymid-y;
/*int*/ var pr2 = x_off*x_off + y_off*y_off; //radius from pixel to pic mid, squared.
/*float*/ var sf2 = pr2 * rMax2_inv; // Scaling factor squared.
/*float*/ var scale = zoom *(0.24*sf2*sf2 + 0.22*sf2 + 1.0); //barrel distortion function
/*float*/ var new_x_off = scale * x_off;
/*float*/ var newx = xmid - new_x_off;
/*float*/ var new_y_off = scale * y_off;
/*float*/ var newy = ymid - new_y_off;
It could probably be optimized even more, like not actually producing some of the variables, like new_y_off, or pix2D temporary array.
Not that it matters a lot in this situation, but still it is useful thing.
I am developing a radar which consists of concentric circular sectors using Raphael JS library. I have been able to create these sectors, however, I am having difficulty thinking up a suitable solution of how points (which are basically simple Raphael shapes- circles, triangles, etc) can be placed within each sector.
I am not sure but does a possible solution lie in using the getBBox() for each path? Keeping in mind that the bounding box for circular shapes have points that are not within the shape itself.
Draw a random invisible path inside the region
get a random point inside that path
and draw a random object using that point as center
var radius1 = 80;
var radius2 = 50;
var center = 250;
function circleToPath(c, r, d) {
if(d == 1) {
return "M "+(c-r)+","+c+" q 0,-"+r+" "+r+",-"+r+" "+r+",0 "+r+","+r+" 0,"+r+" -"+r+","+r+" -"+r+",0 "+"-"+r+",-"+r;
} else {
return "M "+(c-r)+","+c+" q 0,"+r+" "+r+","+r+" "+r+",0 "+r+",-"+r+" 0,-"+r+" -"+r+",-"+r+" -"+r+",0 "+"-"+r+","+r;
}
}
region = paper.path(circleToPath(center, radius1, 1) + circleToPath(center, radius2, 0) + "z").attr({fill: "red", "fill-opacity": 0.5,stroke: "none"});
for(i=0;i<5;i++){
randomRadius = Math.floor((Math.random() * (radius1 - radius2)) + radius2);
vir = paper.path(circleToPath(center, randomRadius, 1)).attr({fill: "none", stroke: "none"});
len = vir.getTotalLength();
pointCenter = vir.getPointAtLength(Math.floor(Math.random() * len));
paper.circle(pointCenter.x,pointCenter.y,(Math.floor(Math.random() * 15)) + 5);
}
http://jsfiddle.net/5L9g0xh4/
UPDATE:
A little bit cheating as path intersection exists but is not working well in Raphael
constrain the random point and then rotate each:
http://jsfiddle.net/crockz/opqhas0w/
I am trying to make a circle out of arcs (something similar to a donut chart is what i am trying to achieve visually) and I succeeded. But, the edges look like a 4 year old drew them!
This is how i'm drawing my arcs:
var arc = new Kinetic.Shape({
drawFunc: function(canvas) {
var context = canvas.getContext('2d');
var x = Math.round(canvas.width / 2);
var y = Math.round(canvas.height / 2);
var radius = 210;
var startAngle = 1.44 * Math.PI;
var endAngle = 1.83 * Math.PI;
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = 175;
canvas.fillStroke(this);
},
stroke: '#121b21',
strokeWidth: 175
});
I created an example fiddle.
I am new to canvas so i figured its probably me...
Can someone please let me know if i am doing something wrong here?
Thank you!
This is the thick-stroke-arc bug present in WebKit browsers. It's probably due to some rounding problem in the arc drawing code. You'll find it looks fine in other browsers most likely. For Webkit, you can use another method to draw these wedges meanwhile.
Possible workarounds:
Use the method you have now, but put a white circle in the middle once you're done with the wedges to blot out the interior irregularities
Use Kinetic.Wedge instead of context.arc.
I'm looking for someone to help guide me in the right direction for a function I'm trying to create.
I need to create an arrow that when at a certain point of degree, a tree grows, I have created 7 different heights and 7 different images for the tree's for a clean look.
Basically you know how you can have an image and rotate it using
<script type="text/javascript">
var img = $('.image');
if(img.length > 0){
var offset = img.offset();
function mouse(evt){
var center_x = (offset.left) + (img.width()/2);
var center_y = (offset.top) + (img.height()/2);
var mouse_x = evt.pageX; var mouse_y = evt.pageY;
var radians = Math.atan2(mouse_x - center_x, mouse_y - center_y);
var degree = (radians * (180 / Math.PI) * -1) + 90;
img.css('-moz-transform', 'rotate('+degree+'deg)');
img.css('-webkit-transform', 'rotate('+degree+'deg)');
img.css('-o-transform', 'rotate('+degree+'deg)');
img.css('-ms-transform', 'rotate('+degree+'deg)');
}
$(document).mousemove(mouse);
}
</script>
But how do I get my arrow to stop at 20 degree's, 25 degree's, 30 degree's etc etc.. while at the same time loading the new image i have assigned to that certain degree (whatever the tip of the arrow is pointed at) all doing this by hover over.
And not only do stop and load the new image, but also once the user clicks submit it adds data to my tree table within my db. So basically, its an arrow, the tip of the arrow gets set at a certain degree, loads the new image, takes the height of the image (i need some way of assigning the height var to each individual image im guessing?) then query that into my tree table under the tree height field.
Any help, links to get me started would be greatly appreciated.
Also, is there a way to do this with Canvas or SVG? Instead of using a arrow image as my arrow? For a more clean look.
Here is an example of how you might render an arrow following the mouse using canvas.
http://jsbin.com/inufoy/edit
Locking the rotation of the arrow to certain points is as simple as filtering the parameter on the draw function. eg:
var segs = 7;
var coefficient = Math.PI / segs;
r -= ((r + coefficient) % (coefficient * 2)) - coefficient;
From there all you have to do is assign each image a rotation, and check when the arrow is pointing towards the tree, then load the tree's image.
Edit:
Here's another version of that script with a static arrow base such as your description:
http://jsbin.com/inufoy/5/edit