问题
i followed this tutorial to build a one handed clock
<!-- language: lang-js -->
window.onload = function(){
var canvas = Raphael("pane",0,0,500,500);
canvas.circle(200,150,100).attr("stroke-width",2);
canvas.circle(200,150,3).attr("fill","#000");
var angleplus = 360,rad = Math.PI / 180,
cx = 200,cy =150 ,r = 85,
startangle = -90,angle=15,x,y, endangle;
for(i=1;i<=24;i++)
{
endangle = startangle + angle ;
x = cx + r * Math.cos(endangle * rad);
y = cy + r * Math.sin(endangle * rad);
canvas.text(x,y,""+(i%24));
startangle = endangle;
}
move = function(dx,dy){
if(dx >=0 && dy <= 85)
this.rotate(dx*0.25,200,150);
},
start = function(){
},
up = function(){};
var hand = canvas.path("M200 70L200 150").attr("stroke-width",3);
hand.drag(move,start,up);
};
Now i want the clock hand to be draggable (touchable via smartphones) to set a certain time. I don't want the clock to run, I just need it as an input device. I know how to calculate the angle but unfortunately I am not able to get the clicked mouse position only relative values to I don't know what. Does anybody have an idea?
EDIT: Now it should hopefully work. I also got it to run ... more or less. It is still a bit jumpy and there are a few points I still want to improve:
- Prevent the circle from getting dragged
- Having influence on the clock by the spinner
- Using / Trying the actual start,end,move functions (I still couldn't succeed)
- ...
回答1:
This will allow you to drag any of the hands, if this is the sort of thing you are after. There may be an easier way, but can't think of it for the moment.
We need to get the transform from the screen to the element (so that they are in the same coordinate space), getScreenCTM() will give us this, and we'll need to find the inverse to apply. (there may be a simpler way if everything is static and no transforms, but often elements are changed by various transforms and catches us out later).
We can get that transform matrix from
this.node.getScreenCTM().inverse()
We'll need to get the x,y from the Raph event and put it as an svg point so we can transfom, eg..
var pt = this.node.ownerSVGElement.createSVGPoint();
pt.x = x; pt.y = y;
var newpt = pt.matrixTransform( this.node.getScreenCTM().inverse() );
So the whole lot would look like...
hour_hand.drag( move, start, end );
minute_hand.drag( move, start, end );
hand.drag( move, start, end );
function move (dx,dy,x,y) {
var pt = this.node.ownerSVGElement.createSVGPoint();
pt.x = x; pt.y = y;
var newpt = pt.matrixTransform( this.node.getScreenCTM().inverse() );
var angle = ( 90 + Math.atan2(pt.y - clock.attr('cy') - 5, pt.x - clock.attr('cx') - 5 ) * 180 / Math.PI + 360) % 360;
this.rotate(angle, 200,150);
this.angle = angle;
}
function start() {}
function end() {
alert( parseInt( this.angle / 30 ) )
}
jsfiddle - drag arms to move
Edit: If you just want a click to move the 2nd hand for example, here is a slight modification, same principle, apart from I've put a background white rect in there to put the click handler on.
jsfiddle - click to move 2nd hand
Edit: There's an improved fiddle here which takes into account various postions of the clock with respect to other html on the screen etc. Where I've added the following...
var cpt = clock.node.ownerSVGElement.createSVGPoint();
cpt.x = clock.attr('cx');
cpt.y = clock.attr('cy');
cpt = cpt.matrixTransform(clock.node.getScreenCTM());
to take into account any position on the screen of the clock, and removed a bit of other redundant code.
来源:https://stackoverflow.com/questions/30500849/one-handed-draggable-clock-with-raphael-cannot-get-mouse-click-position