Raphael pie chart - draw paths anticlockwise - javascript

I'm trying to take the demo pie from the Raphael.js (http://raphaeljs.com/pie.html) and draw it clockwise - currently it's being drawn anticlockwise which doesn't make an awful lot of sense. This jsfiddle is the code from the demo:
http://jsfiddle.net/6bWuT/
On line 14 (beginning 'return paper.path' below) changing the second 0 to a 1 should change the rotation to clockwise but actually just screws the plot. Any help would be massively appreciated :) thanks in advance.
Code from the fiddle for reference:
Raphael.fn.pieChart = function (cx, cy, r, values, labels, stroke) {
var paper = this,
rad = Math.PI / 180,
chart = this.set();
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 angle = 0,
total = 0,
start = 0,
process = function (j) {
var value = values[j],
angleplus = 360 * value / total,
popangle = angle + (angleplus / 2),
color = Raphael.hsb(start, .75, 1),
ms = 500,
delta = 30,
bcolor = Raphael.hsb(start, 1, 1),
p = sector(cx, cy, r, angle, angle + angleplus, {fill: "90-" + bcolor + "-" + color, stroke: stroke, "stroke-width": 3}),
txt = paper.text(cx + (r + delta + 55) * Math.cos(-popangle * rad), cy + (r + delta + 25) * Math.sin(-popangle * rad), labels[j]).attr({fill: bcolor, stroke: "none", opacity: 0, "font-size": 20});
p.mouseover(function () {
p.stop().animate({transform: "s1.1 1.1 " + cx + " " + cy}, ms, "elastic");
txt.stop().animate({opacity: 1}, ms, "elastic");
}).mouseout(function () {
p.stop().animate({transform: ""}, ms, "elastic");
txt.stop().animate({opacity: 0}, ms);
});
angle += angleplus;
chart.push(p);
chart.push(txt);
start += .1;
};
for (var i = 0, ii = values.length; i < ii; i++) {
total += values[i];
}
for (i = 0; i < ii; i++) {
process(i);
}
return chart;
};
$(function () {
var values = [],
labels = [];
$("tr").each(function () {
values.push(parseInt($("td", this).text(), 10));
labels.push($("th", this).text());
});
$("table").hide();
Raphael("holder", 700, 700).pieChart(350, 350, 200, values, labels, "#fff");
});

Oop, found it.. change the sector function:
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, 1, +(endAngle - startAngle > 180), 0, x2, y2, "z"]).attr(params);
}
The cos and sin are now being made to positive numbers instead of negative, and the 0 is changed to a 1 on the paper.path line.
Win! :)

Related

Js - calculate distance from point mapped to colour forms square?

I am working on a project where I visualise the effect of a magnetic dipole, on a range of vectors, I'm just testing with one pole at the moment and something doesn't work but I don't know why.
the force that a vector receives is mapped onto a color to check if I did it right, these are my results:
so this is the canvas I'm working with
and when I lower the size of each vector and increase the density you can see this forms diamonds rather than a circular pattern.
Does anybody know why this is or what could be causing it?
code below here:
function calcForce(magnet, vector){
return 1/distance(magnet.x,magnet.y,vector.centerx,vector.centery) * magnet.force;
}
function distance(cx, cy, ex, ey){
var dy = Math.abs(ey - cy);
var dx = Math.abs(ex - cx);
return Math.sqrt((dx^2) + (dy^2));
}
function mapRainbow(value) {
return 'hsl(' + value + ',100%,50%)';
}
function map_range(value, low1, high1, low2, high2) {
return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
}
function mapForce(force){
return map_range(force,10,1000,20,40);
}
function drawStroke(stroke){
ctx.beginPath();
ctx.moveTo(stroke.x1,stroke.y1);
ctx.lineTo(stroke.x2,stroke.y2);
stroke.color = mapRainbow(stroke.force);
ctx.strokeStyle = stroke.color;
ctx.stroke();
ctx.closePath();
}
*this is not all the code by far but I think this is enough, need to see more? just ask.
Use distance to generate gradient:
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 500;
canvas.height = 500;
document.body.appendChild(canvas);
function distance(x1, y1, x2, y2) {
return Math.sqrt((x2 -= x1) * x2 + (y2 -= y1) * y2);
}
function angleBetweenPoints(x1, y1, x2, y2) {
return (Math.atan2(x2 - x1, y2 - y1) + 2 * Math.PI);
}
var center = { x: 250, y: 250 };
var vectorLength = 15;
function max(v, m) {
if (v > m) {
return m;
}
return v;
}
function draw() {
if (Math.random() > 0.5) {
center.x += (Math.random() - 0.5) * 10;
}
else {
center.y += (Math.random() - 0.5) * 10;
}
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var xIndex = 0; xIndex < canvas.width; xIndex += vectorLength) {
for (var yIndex = 0; yIndex < canvas.height; yIndex += vectorLength) {
var x = xIndex - (Math.random() * vectorLength * 0.0);
var y = yIndex - (Math.random() * vectorLength * 0.0);
var angle = angleBetweenPoints(center.x, center.y, x, y);
var dist = distance(x, y, center.x, center.y);
ctx.fillStyle = "rgb(" + Math.floor(max(dist, 255)) + "," + Math.floor((255 - max(dist, 255))) + ",0)";
ctx.translate((x + vectorLength * 0.5), (y + vectorLength * 0.5));
ctx.rotate(-angle);
ctx.fillRect(0 - vectorLength * 0.5, 0 - vectorLength * 0.5, vectorLength * 0.25, vectorLength * 0.75);
ctx.rotate(angle);
ctx.translate(0 - (x + vectorLength * 0.5), 0 - (y + vectorLength * 0.5));
}
}
ctx.fillRect(center.x + vectorLength / 2, center.y + vectorLength / 2, vectorLength, vectorLength);
requestAnimationFrame(function () {
setTimeout(draw, 1000 / 60);
});
}
draw();

FabricJs - Radial gradient for pie pieces

As you see here: http://jsfiddle.net/Da7SP/60/ I have 64 pie pieces that I want to have a radial gradient from the middle out to the edge. (Live each piece will have different colors) but I don't succeed to create that effect.
Here is the code:
var canvas = window._canvas = new fabric.Canvas('c');
var x=300
, y=300
, totalGates=64
, start=0
, radius=200
, val = 360 / totalGates;
for (var i = 0; i < totalGates; i++) {
createPath(x, y, radius, val*i, (val*i)+val);
}
function createPath (x, y, radius, startAngle, endAngle) {
var flag = (endAngle - startAngle) > 180;
startAngle = (startAngle % 360) * Math.PI / 180;
endAngle = (endAngle % 360) * Math.PI / 180;
var path = 'M '+x+' '+y+' l ' + radius * Math.cos(startAngle) + ' ' + radius * Math.sin(startAngle) +
' A ' + radius + ' ' + radius + ' 0 ' + (+flag) + ' 1 ' + (x + radius * Math.cos(endAngle))+ ' ' + (y + radius * Math.sin(endAngle)) + ' z';
var piePiece = new fabric.Path(path);
piePiece.set({
strokeWidth:0
});
piePiece.setGradient('fill', {
type:'radial',
x1: x,
y1: y,
//x2: x + radius * Math.cos(endAngle),
//y2: y + radius * Math.sin(endAngle),
r1: radius,
r2: 0,
colorStops: {
0: '#000',
1: '#fff',
}
});
canvas.add(piePiece);
}
I thought that it would be enough to set x1 to x and y1 to y to define the coordinates for the middle and then the radius, (before when I used PathGroup that did the trick). but now when I add the Path to a Group or directly to the Canvas the gradient looks completely different.
So, how do I use the setGradient with a radial gradient so it is displayed as if the complete pie was a circle, it would go from the center to the edge
Update:
I noticed that if I set x=0 and y=0 then the gradient get centered.
Update2:
If both x1 and y2 is set to 0 the gradient is drawn from the top left corner, this makes the gradient looks good in the 90 degree bottom - right corner: http://jsfiddle.net/Da7SP/61/
Update3:
I solved it! Here http://jsfiddle.net/Da7SP/64/ is the Fiddle for you who has the same problem and below you see the result and the code.
This made the trick:
x1: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
y1: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
x2: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
y2: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
Here is the expected result:
Here is the code
var canvas = window._canvas = new fabric.Canvas('c');
var x=300
, y=300
, totalGates=64
, start=0
, radius=200
, val = 360 / totalGates;
/* Loops through each gate and prints selected options */
for (var i = 0; i < totalGates; i++) {
createPath(x, y, radius, val*i, (val*i)+val, i);
}
function createPath (x, y, radius, startAngle, endAngle,i ) {
var flag = (endAngle - startAngle) > 180;
startAngle = (startAngle % 360) * Math.PI / 180;
endAngle = (endAngle % 360) * Math.PI / 180;
var path = 'M '+x+' '+y+' l ' + radius * Math.cos(startAngle) + ' ' + radius * Math.sin(startAngle) +
' A ' + radius + ' ' + radius + ' 0 ' + (+flag) + ' 1 ' + (x + radius * Math.cos(endAngle))+ ' ' + (y + radius * Math.sin(endAngle)) + ' z';
var piePiece = new fabric.Path(path);
piePiece.set({
strokeWidth:0
});
piePiece.setGradient('fill', {
type:'radial',
x1: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
y1: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
x2: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
y2: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
r1: radius,
r2: 0,
colorStops: {
0: '#000',
1: '#f0f',
}
});
canvas.add(piePiece);
}
Here is the code that was missing:
piePiece.setGradient('fill', {
type:'radial',
x1: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
y1: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
x2: x > Math.round(piePiece.left) ? x - piePiece.left : 0,
y2: y > Math.round(piePiece.top) ? y - piePiece.top : 0,
r1: radius,
r2: 0,
colorStops: {
0: '#000',
1: '#f0f',
}
});

Raphael Graph - set fixed range

I'd like to be able to cater for missing graph points by breaking the graph line where data is missing.
I think I can achieve this by specifying a fixed range?
For example, if the x-axis should contain every hour in the day and the y-axis contains percentage values, I want the x-axis to always have a full range of 24 hour values.
However, the code is taking the set of times for which data exists and is using them as the range for the x-axis. If no data was present for times between 4 - 11 then the graph shows a straight line between 4 and 11, 5,6,7,8,9 and 10 don't appear on the x-axis and this is not what I want.
Here is the code...
Raphael.fn.drawGrid = function (x, y, w, h, wv, hv, color) {
color = color || "#000";
var path = ["M", Math.round(x) + .5, Math.round(y) + .5, "L", Math.round(x + w) + .5, Math.round(y) + .5, Math.round(x + w) + .5, Math.round(y + h) + .5, Math.round(x) + .5, Math.round(y + h) + .5, Math.round(x) + .5, Math.round(y) + .5],
rowHeight = h / hv,
columnWidth = w / wv;
for (var i = 1; i < hv; i++) {
path = path.concat(["M", Math.round(x) + .5, Math.round(y + i * rowHeight) + .5, "H", Math.round(x + w) + .5]);
}
for (i = 1; i < wv; i++) {
path = path.concat(["M", Math.round(x + i * columnWidth) + .5, Math.round(y) + .5, "V", Math.round(y + h) + .5]);
}
return this.path(path.join(",")).attr({stroke: color});
};
$(function () {
$("#data").css({
position: "absolute",
left: "-9999em",
top: "-9999em"
});
});
window.onload = function () {
function getAnchors(p1x, p1y, p2x, p2y, p3x, p3y) {
var l1 = (p2x - p1x) / 2,
l2 = (p3x - p2x) / 2,
a = Math.atan((p2x - p1x) / Math.abs(p2y - p1y)),
b = Math.atan((p3x - p2x) / Math.abs(p2y - p3y));
a = p1y < p2y ? Math.PI - a : a;
b = p3y < p2y ? Math.PI - b : b;
var alpha = Math.PI / 2 - ((a + b) % (Math.PI * 2)) / 2,
dx1 = l1 * Math.sin(alpha + a),
dy1 = l1 * Math.cos(alpha + a),
dx2 = l2 * Math.sin(alpha + b),
dy2 = l2 * Math.cos(alpha + b);
return {
x1: p2x - dx1,
y1: p2y + dy1,
x2: p2x + dx2,
y2: p2y + dy2
};
}
// Grab the data
var labels = [],
data = [];
$("#data tfoot th").each(function () {
labels.push($(this).html());
});
$("#data tbody td").each(function () {
data.push($(this).html());
});
// Draw
var width = 800,
height = 250,
leftgutter = 30,
bottomgutter = 20,
topgutter = 20,
colorhue = .6 || Math.random(),
color = "hsl(" + [colorhue, .5, .5] + ")",
r = Raphael("holder", width, height),
txt = {font: '12px Helvetica, Arial', fill: "#fff"},
txt1 = {font: '10px Helvetica, Arial', fill: "#fff"},
txt2 = {font: '12px Helvetica, Arial', fill: "#000"},
X = (width - leftgutter) / labels.length,
max = Math.max.apply(Math, data),
Y = (height - bottomgutter - topgutter) / max;
r.drawGrid(leftgutter + X * .5 + .5, topgutter + .5, width - leftgutter - X, height - topgutter - bottomgutter, 10, 10, "#000");
var path = r.path().attr({stroke: color, "stroke-width": 4, "stroke-linejoin": "round"}),
bgp = r.path().attr({stroke: "none", opacity: .3, fill: color}),
label = r.set(),
lx = 0, ly = 0,
is_label_visible = false,
leave_timer,
blanket = r.set();
label.push(r.text(60, 12, "24 hits").attr(txt));
label.push(r.text(60, 27, "22 September 2008").attr(txt1).attr({fill: color}));
label.hide();
var frame = r.popup(100, 100, label, "right").attr({fill: "#000", stroke: "#666", "stroke-width": 2, "fill-opacity": .7}).hide();
var p, bgpp;
for (var i = 0, ii = labels.length; i < ii; i++) {
var y = Math.round(height - bottomgutter - Y * data[i]),
x = Math.round(leftgutter + X * (i + .5)),
t = r.text(x, height - 6, labels[i]).attr(txt).toBack();
if (!i) {
p = ["M", x, y, "C", x, y];
bgpp = ["M", leftgutter + X * .5, height - bottomgutter, "L", x, y, "C", x, y];
}
if (i && i < ii - 1) {
var Y0 = Math.round(height - bottomgutter - Y * data[i - 1]),
X0 = Math.round(leftgutter + X * (i - .5)),
Y2 = Math.round(height - bottomgutter - Y * data[i + 1]),
X2 = Math.round(leftgutter + X * (i + 1.5));
var a = getAnchors(X0, Y0, x, y, X2, Y2);
p = p.concat([a.x1, a.y1, x, y, a.x2, a.y2]);
bgpp = bgpp.concat([a.x1, a.y1, x, y, a.x2, a.y2]);
}
var dot = r.circle(x, y, 4).attr({fill: "#333", stroke: color, "stroke-width": 2});
blanket.push(r.rect(leftgutter + X * i, 0, X, height - bottomgutter).attr({stroke: "none", fill: "#fff", opacity: 0}));
var rect = blanket[blanket.length - 1];
(function (x, y, data, lbl, dot) {
var timer, i = 0;
rect.hover(function () {
clearTimeout(leave_timer);
var side = "right";
if (x + frame.getBBox().width > width) {
side = "left";
}
var ppp = r.popup(x, y, label, side, 1),
anim = Raphael.animation({
path: ppp.path,
transform: ["t", ppp.dx, ppp.dy]
}, 200 * is_label_visible);
lx = label[0].transform()[0][1] + ppp.dx;
ly = label[0].transform()[0][2] + ppp.dy;
frame.show().stop().animate(anim);
label[0].attr({text: data + " hit" + (data == 1 ? "" : "s")}).show().stop().animateWith(frame, anim, {transform: ["t", lx, ly]}, 200 * is_label_visible);
label[1].attr({text: lbl + " September 2008"}).show().stop().animateWith(frame, anim, {transform: ["t", lx, ly]}, 200 * is_label_visible);
dot.attr("r", 6);
is_label_visible = true;
}, function () {
dot.attr("r", 4);
leave_timer = setTimeout(function () {
frame.hide();
label[0].hide();
label[1].hide();
is_label_visible = false;
}, 1);
});
})(x, y, data[i], labels[i], dot);
}
p = p.concat([x, y, x, y]);
bgpp = bgpp.concat([x, y, x, y, "L", x, height - bottomgutter, "z"]);
path.attr({path: p});
bgp.attr({path: bgpp});
frame.toFront();
label[0].toFront();
label[1].toFront();
blanket.toFront();
};

Raphael js. Fill color along a curve

I have created a circle in which I can choose two points along the circumference of of circle.
I want to fill the portion between those two points.
Demo
If you see the demo, I want to fill the angle between two points.
JS:
(function (Raphael) {
Raphael.colorwheel = function (x, y, size, initcolor, element) {
return new ColorWheel(x, y, size, initcolor, element);
};
var pi = Math.PI,
doc = document,
win = window,
ColorWheel = function (x, y, size, initcolor, element) {
size = size || 200;
var w3 = 3 * size / 200,
w1 = size / 200,
fi = 1.6180339887,
segments = 3,//pi * size / 50,
size20 = size / 20,
size2 = size / 2,
padding = 2 * size / 200,
t = this;
var H = 1, S = 1, B = 1, s = size - (size20 * 4);
var r = element ? Raphael(element, size, size) : Raphael(x, y, size, size),
xy = s / 6 + size20 * 2 + padding,
wh = s * 2 / 3 - padding * 2;
w1 < 1 && (w1 = 1);
w3 < 1 && (w3 = 1);
// ring drawing
var a = pi / 2 - pi * 2 / segments * 1.3,
R = size2 - padding,
R2 = size2 - padding - size20 * 2,
path = ["M", size2, padding, "A", R, R, 0, 0, 1, R * Math.cos(a) + R + padding, R - R * Math.sin(a) + padding, "L", R2 * Math.cos(a) + R + padding, R - R2 * Math.sin(a) + padding, "A", R2, R2, 0, 0, 0, size2, padding + size20 * 2, "z"].join();
for (var i = 0; i < segments; i++) {
r.path(path).attr({
stroke: "none",
fill: "#8fd117",
transform: "r" + [(360 / segments) * i, size2, size2]
});
}
r.path(["M", size2, padding, "A", R, R, 0, 1, 1, size2 - 1, padding, "l1,0", "M", size2, padding + size20 * 2, "A", R2, R2, 0, 1, 1, size2 - 1, padding + size20 * 2, "l1,0"]).attr({
"stroke-width": w3,
stroke: "#fff"
});
t.startCursor = r.set();
var h = size20 * 2 + 2;
t.startCursor.push(r.rect(size2 - h / fi / 2, padding - 1, h / fi, h, 3 * size / 200).attr({
stroke: "#00A0C6",
opacity: .5,
"stroke-width": w3
}));
t.startCursor.push(t.startCursor[0].clone().attr({
stroke: "#00A0C6",
opacity: 1,
"stroke-width": w1
}));
t.endCursor = r.set();
var h = size20 * 2 + 2;
t.endCursor.push(r.rect(size2 - h / fi / 2, padding - 1, h / fi, h, 3 * size / 200).attr({
stroke: "#F96E5B",
opacity: .5,
"stroke-width": w3
}));
t.endCursor.push(t.endCursor[0].clone().attr({
stroke: "#F96E5B",
opacity: 1,
"stroke-width": w1
}));
t.ring = r.path(["M", size2, padding, "A", R, R, 0, 1, 1, size2 - 1, padding, "l1,0M", size2, padding + size20 * 2, "A", R2, R2, 0, 1, 1, size2 - 1, padding + size20 * 2, "l1,0"]).attr({
fill: "#000",
opacity: 0,
stroke: "none"
});
t.H = t.S = t.B = 1;
t.raphael = r;
t.size2 = size2;
t.wh = wh;
t.x = x;
t.xy = xy;
t.y = y;
t.endCursor.attr({transform: "r" + [50, t.size2, t.size2]});
// events
t.ring.drag(function (dx, dy, x, y) {
t.docOnMove(dx, dy, x, y);
}, function (x, y) {
// Rotate on click
t.setH(x - t.x - t.size2, y - t.y - t.size2);
}, function () {
});
},
proto = ColorWheel.prototype;
proto.setH = function (x, y) {
var d = Raphael.angle(x, y, 0, 0);
this.H = (d + 90) / 360;
var a = 0;
if(d > 270) {
d = d - 270;
}
else {
d = d + 90;
}
var m = Math.abs(d - this.startCursor[0]._.deg);
var n = Math.abs(d - this.endCursor[0]._.deg);
if(m > 180) {
m = 360 - m ;
}
if(n > 180) {
n = 360 - n;
}
if( m <= n) {
this.startCursor.attr({transform: "r" + [d, this.size2, this.size2]});
}
else {
this.endCursor.attr({transform: "r" + [d, this.size2, this.size2]});
}
m = this.startCursor[0]._.deg ;
n = this.endCursor[0]._.deg;
if(m > 360) {
m = m - 360;
}
if( n > 360 ) {
n = n - 360;
}
var diff = m > n ? m - n : n - m;
this.onchange(m,n,diff);
};
proto.docOnMove = function (dx, dy, x, y) {
this.setH(x - this.x - this.size2, y - this.y - this.size2);
};
})(window.Raphael);
window.onload = function () {
var cp2 = Raphael.colorwheel(60, 20, 200, "#eee");
var X = document.getElementById('x');
var Y = document.getElementById('y');
var angle = document.getElementById('angle');
cp2.onchange = function (x, y, ang) {
X.innerHTML = Math.round(x * 100) / 100;
Y.innerHTML = Math.round(y * 100) / 100;
angle.innerHTML = Math.round(ang * 100) / 100;
}
};
HTML:
<div id="wrapper">X : <span id="x">0</span>
<br>Y: <span id="y">50</span>
<br>Angle: <span id="angle">50</span>
</div>
CSS:
body {
background: #e6e6e6;
}
#wrapper {
position: absolute;
top: 240px;
left: 100px;
}
UPDATE:
With Chris's help,
I have got some success.
See Demo
Bugs :
1. If you start green first, red breaks,
2. If you start red first and makes angle of greater than 180 degree and when green reduces that below 180 degree, it breaks again.
UPDATE 2
DEMO
BUGS:
1. If you start red first and makes angle of greater than 180 degree and when green reduces that below 180 degree, it breaks again.
2. Sometimes arcs in opposite direction.
Cool project. You just need to add an elliptical arc to the color wheel and redraw the path on the onchange event.
I got you half the way here: It works if you move the orange cursor, completely breaks if you move the blue cursor.
To start:
t.x0 = t.startCursor[0].attr("x") + t.startCursor[0].attr("width") / 2;
t.y0 = t.startCursor[0].attr("y") + t.startCursor[0].attr("height") / 2;
t.R1 = (R2 + R) / 2;
t.x1 = t.x0 + t.R1 * Math.sin(50 * Math.PI / 180);
t.y1 = t.y0 + t.R1 - t.R1 * Math.cos(50 * Math.PI / 180);
t.arc = r.path("M" + t.x0 + "," + t.y0 + "A" + t.R1 + "," + t.R1 + " 50 0,1 " + t.x1 + "," + t.y1)
.attr({
stroke: "#009900",
"stroke-width": 10
});
On update:
if (n > 180) {
flag = 1;
}
var diff = m > n ? m - n : n - m;
t.x0 = t.x0 + t.R1 * Math.sin(m * Math.PI / 180);
t.y0 = t.y0 + t.R1 - t.R1 * Math.cos(m * Math.PI / 180);
t.x1 = t.x0 + t.R1 * Math.sin(diff * Math.PI / 180);
t.y1 = t.y0 + t.R1 - t.R1 * Math.cos(diff * Math.PI / 180);
t.arc = t.arc.attr("path", "M" + t.x0 + "," + t.y0 + "A" + t.R1 + "," + t.R1 + " " + diff + " " + flag + ",1 " + t.x1 + "," + t.y1);
jsfiddle
Should be able to take it from here.
UPDATE, May 8:
You can fix your first problem by changing the flag on the diff, not on the second angle:
if (diff > 180) {
flag = 1;
}
The event that's triggering the second problem is the second angle (the red handle) passing the 0-degree mark. The easiest way to catch this is just to add 360 to the angle IF it's less than the first angle:
var m = this.startCursor[0]._.deg ;
var n = this.endCursor[0]._.deg;
var t = this;
var flag = 0;
var sweep = 1;
var path = "";
if (n < m) {
m += 360;
}
var diff = Math.abs(m - n);
if (diff > 180) {
flag = 1;
}
Here's the fiddle
Note: You were catching situations where (n > 360) and (m > 360), but this doesn't appear necessary -- the angles arrive at this point in the code already set below 360, at least in Chrome.
Here's working solution:
Demo
(function (Raphael) {
Raphael.colorwheel = function (x, y, size, initcolor, element) {
return new ColorWheel(x, y, size, initcolor, element);
};
var pi = Math.PI,
doc = document,
win = window,
ColorWheel = function (x, y, size, initcolor, element) {
size = size || 200;
var w3 = 3 * size / 200,
w1 = size / 200,
fi = 1.6180339887,
segments = 3,//pi * size / 50,
size20 = size / 20,
size2 = size / 2,
padding = 2 * size / 200,
t = this;
var H = 1, S = 1, B = 1, s = size - (size20 * 4);
var r = element ? Raphael(element, size, size) : Raphael(x, y, size, size),
xy = s / 6 + size20 * 2 + padding,
wh = s * 2 / 3 - padding * 2;
w1 < 1 && (w1 = 1);
w3 < 1 && (w3 = 1);
// ring drawing
var a = pi / 2 - pi * 2 / segments * 1.3,
R = size2 - padding,
R2 = size2 - padding - size20 * 2,
path = ["M", size2, padding, "A", R, R, 0, 0, 1, R * Math.cos(a) + R + padding, R - R * Math.sin(a) + padding, "L", R2 * Math.cos(a) + R + padding, R - R2 * Math.sin(a) + padding, "A", R2, R2, 0, 0, 0, size2, padding + size20 * 2, "z"].join();
for (var i = 0; i < segments; i++) {
r.path(path).attr({
stroke: "none",
fill: "#8fd117",
transform: "r" + [(360 / segments) * i, size2, size2]
});
}
r.path(["M", size2, padding, "A", R, R, 0, 1, 1, size2 - 1, padding, "l1,0", "M", size2, padding + size20 * 2, "A", R2, R2, 0, 1, 1, size2 - 1, padding + size20 * 2, "l1,0"]).attr({
"stroke-width": w3,
stroke: "#fff"
});
t.startCursor = r.set();
var h = size20 * 2 + 2;
t.startCursor.push(r.rect(size2 - h / fi / 2, padding - 1, h / fi, h, 3 * size / 200).attr({
stroke: "#00A0C6",
opacity: 1,
"stroke-width": w3
}));
t.startCursor.push(t.startCursor[0].clone().attr({
stroke: "#00A0C6",
fill : "#8fd117",
opacity: 1,
"stroke-width": w1
}));
t.endCursor = r.set();
var h = size20 * 2 + 2;
t.endCursor.push(r.rect(size2 - h / fi / 2, padding - 1, h / fi, h, 3 * size / 200).attr({
stroke: "#F96E5B",
opacity: 1,
"stroke-width": w3,
}));
t.endCursor.push(t.endCursor[0].clone().attr({
stroke: "#F96E5B",
fill : "#8fd117",
opacity: 1,
"stroke-width": w1
}));
t.ring = r.path(["M", size2, padding, "A", R, R, 0, 1, 1, size2 - 1, padding, "l1,0M", size2, padding + size20 * 2, "A", R2, R2, 0, 1, 1, size2 - 1, padding + size20 * 2, "l1,0"]).attr({
fill: "#000",
opacity: 0,
stroke: "none"
});
t.H = t.S = t.B = 1;
t.raphael = r;
t.size2 = size2;
t.wh = wh;
t.x = x;
t.xy = xy;
t.y = y;
t.endCursor.attr({transform: "r" + [50, t.size2, t.size2]});
t.x0 = t.startCursor[0].attr("x") + t.startCursor[0].attr("width") / 2;
t.y0 = t.startCursor[0].attr("y") + t.startCursor[0].attr("height") / 2;
t.initX0 = t.x0;
t.initY0 = t.y0;
t.R1 = (R2 + R) / 2;
t.x1 = t.x0 + t.R1 * Math.sin(50 * Math.PI / 180);
t.y1 = t.y0 + t.R1 - t.R1 * Math.cos(50 * Math.PI / 180);
t.initX1 = t.x1;
t.initY1 = t.y1;
var path = "M" + t.x0 + "," + t.y0 + "A" + t.R1 + "," + t.R1 + " 50 0,1 " + t.x1 + "," + t.y1;
t.arc = r.path(path)
.attr({
stroke: "#009900",
"stroke-width": 10
});
t.startCursor.drag(function (dx, dy, x, y) {
t.docOnMove(dx, dy, x, y,'startCursor');
}, function (x, y) {
t.setH(x - t.x - t.size2, y - t.y - t.size2,'startCursor');
}, function () {
});
t.endCursor.drag(function (dx, dy, x, y) {
t.docOnMove(dx, dy, x, y,'endCursor');
}, function (x, y) {
t.setH(x - t.x - t.size2, y - t.y - t.size2,'endCursor');
}, function () {
});
t.startCursor.toFront();
t.endCursor.toFront();
},
proto = ColorWheel.prototype;
proto.setH = function (x, y,cursor) {
var d = Raphael.angle(x, y, 0, 0);
if(d > 270) {
d = d - 270;
}
else {
d = d + 90;
}
if((cursor === 'startCursor' && d > this.endCursor[0]._.deg) || (cursor === 'endCursor' && d <= this.startCursor[0]._.deg)) {
return;
}
if(cursor === 'startCursor') {
this.startCursor.attr({transform: "r" + [d, this.size2, this.size2]});
}
else {
this.endCursor.attr({transform: "r" + [d, this.size2, this.size2]});
}
var m = this.startCursor[0]._.deg ;
var n = this.endCursor[0]._.deg;
var t = this;
var flag = 0;
if(m > 360) {
m = m - 360;
flag = 1;
}
if( n > 360 ) {
n = n - 360;
}
var diff = Math.abs(m - n);
if (diff > 180) {
flag = 1;
}
var path = "";
var sweep = 1;
if(cursor === 'endCursor') {
t.x1 = t.initX0 + t.R1 * Math.sin(n * Math.PI / 180);
t.y1 = t.initY0 + t.R1 - t.R1 * Math.cos(n * Math.PI / 180);
}
else {
t.x0 = t.initX0 + t.R1 * Math.sin(m * Math.PI / 180);
t.y0 = t.initY0 + t.R1 - t.R1 * Math.cos(m * Math.PI / 180);
}
console.log(m,t.x0,t.y0,t.x1,t.y1);
path = "M" + t.x0 + "," + t.y0 + "A" + t.R1 + "," + t.R1 + " " + diff + " " + flag + "," + sweep + " " + t.x1 + "," + t.y1;
t.arc = t.arc.attr("path", path );
this.onchange(m,n,diff);
};
proto.docOnMove = function (dx, dy, x, y,cursor) {
this.setH(x - this.x - this.size2, y - this.y - this.size2,cursor);
};
})(window.Raphael);
window.onload = function () {
var cp2 = Raphael.colorwheel(60, 20, 200, "#eee");
var X = document.getElementById('x');
var Y = document.getElementById('y');
var angle = document.getElementById('angle');
cp2.onchange = function (x, y, ang) {
X.innerHTML = Math.round(x * 100) / 100;
Y.innerHTML = Math.round(y * 100) / 100;
angle.innerHTML = Math.round(ang * 100) / 100;
}
};

raphael.js stroke/path width doesnt seem to work

I'm hacking at a fiddle and cannot control the path width.
see the 2nd last line, really baffling:
var paper = Raphael(20, 20, 320, 320);
function arc(center, radius, startAngle, endAngle) {
angle = startAngle;
coords = toCoords(center, radius, angle);
path = "M " + coords[0] + " " + coords[1];
while(angle<=endAngle) {
coords = toCoords(center, radius, angle);
path += " L " + coords[0] + " " + coords[1];
angle += 1;
}
return path;
}
function toCoords(center, radius, angle) {
var radians = (angle/180) * Math.PI;
var x = center[0] + Math.cos(radians) * radius;
var y = center[1] + Math.sin(radians) * radius;
return [x, y];
}
var ps = paper.path(arc([100, 100], 80, -90, 90));
ps.attr({stroke:'#C00',width:100});
ps.glow({color: '#f00',width: 20});​
here's the fiddle:
http://jsfiddle.net/U5Kpx/5/
can anyone see what I'm doing wrong here?
Thanks very much
You should use stroke-width
eg:
ps.attr({stroke:'#C00',"stroke-width":5});
ps.glow({color: '#f00',width: 40});​
Check this fiddle

Categories

Resources