snap.svg 制作完美 "circle pointer"
snap.svg making a perfect "circle pointer"
首先,抱歉主题名称。我真的不能用一句话准确地解释我想做什么。
那么!我要做的是一个圆,圆上有一个正方形,里面有6个"hoverable"个正方形。
这是我做的测试:
var s = Snap(500, 500);
var thecircle = s.circle(250,250,100).attr({fill:'none',stroke:'red','stroke-width':'2'});
var pointer = s.rect(240,340,20,20);
var william = s.g(thecircle, pointer);
var hover1 = s.rect(240,290,20,20).attr({'value':'0'}).addClass('hovering');
var hover2 = hover1.clone().transform('r60,250,250').attr({'value':'60'}).addClass('hovering');
var hover3 = hover1.clone().transform('r120,250,250').attr({'value':'120'}).addClass('hovering');
var hover4 = hover1.clone().transform('r180,250,250').attr({'value':'180'}).addClass('hovering');
var hover5 = hover1.clone().transform('r240,250,250').attr({'value':'240'}).addClass('hovering');
var hover6 = hover1.clone().transform('r300,250,250').attr({'value':'300'}).addClass('hovering');
var $ = jQuery;
$('.hovering').mouseenter(function(){
var rotate = $(this).attr('value');
william.animate({transform:'r'+rotate+',250,250'},300,mina.ease);
});
这是一个 fiddle 以便您可以检查动画的外观:JSfiddle
现在,看看将第 6 个方块(300 度)悬停然后将第 2 个方块(60 度)悬停时会发生什么。指针将在第 5、4 和 3 之前一直移动到第 2(移动 240 度)。
我想让我的指针走最快的路线到达目的地,在这个例子中,它是 420 度。
但是我不知道如何让它表现得那样,因为我不太擅长数学...
已更新
要解决这个问题,首先我们需要创建一个变量 prevRotate
- 初始设置为 0
- 要记录指针先前位置的值,那么我们需要处理四种特殊情况(1)以及正常情况如下所示:
当指针先前在底部方块上时(rotate
值=0
),鼠标悬停在一个方块上旋转值大于180
,需要将指针逆时针移动-1 * (360 - rotate)
。然后使用回调函数,我们使用动画时间为 [=13= 的 .animate()
函数将旋转度 立即 设置为原始 rotate
值].
当指针原本在rotate
值大于180
的方块上时,悬停在下方方块上其旋转值为 0
,将指针动画化为 360
CW 方向,然后使用我们的回调我们将其重置为 0
.
当指针先前位于 rotate
值为 300
的方块上时,鼠标悬停在方块上 rotate
的值为60
,我们需要从300
到420
(300 + (360-300) + 60
),然后使用回调函数将旋转值重置为60
.
当指针先前位于 rotate
值为 60
的正方形时,我们需要将其设置为正方形 60
=14=] 的 300
,我们需要从 60
动画到 -60
然后立即再次使用回调函数将旋转设置为300
。
最后我们需要更新 prevRotate
的值以便进一步比较。
var $ = jQuery,
prevRotate = 0; // The variable used to store the previous location of the pointer.
$('.hovering').mouseenter(function(){
var rotate = $(this).attr('value');
// Special case 1, moving the pointer CCW following the short route.
if( prevRotate == 0){
var tempR = rotate;
rotate = rotate > 180 ? -1 * (360 - rotate) : rotate;
william.animate({transform:'r' +rotate+ ',250,250'},300,mina.ease, function(){
myCB(tempR);
});
}else{
// Normal case.
william.animate({transform:'r'+ rotate +',250,250'},300,mina.ease);
}
if(rotate == 0){
// Special Case 2, animating to 360 instead of 0, then to 0 immediately.
if(prevRotate > 180){
william.animate({transform:'r360,250,250'},300,mina.ease,function(){
myCB(0);
});
}
}else if(rotate == 60 && prevRotate == 300){
// Special Case 3, animating from 300 to 60 following the short route.
william.animate({transform:'r420,250,250'},300,mina.ease, function(){
myCB(60);
});
}else if(rotate == 300 && prevRotate == 60){
// Special Case 4, animating from 60 to 30 following short route.
william.animate({transform:'r-60,250,250'},300,mina.ease, function(){
myCB(300);
});
}
// Update the value of the pointer's previous location
prevRotate = $(this).attr('value');
});
// The Callback function to reset rotate values.
function myCB(theAngle){
william.animate({transform:'r' +theAngle+ ',250,250'},0);
}
(1) 请注意,您可以像这样将特殊情况 3 和 4 代码块合并为一个:
if((rotate == 60 || rotate == 300) && prevRotate == 360 - rotate){
// Define the destination angle depending on value of rotate
var newR = (rotate == 60) ? 420 : -60;
william.animate({transform:'r' +newR+ ',250,250'},300,mina.ease,function(){
myCB(prevRotate);
});
}
你只需要计算出两个可能方向中哪个方向的距离最短。然后将最小的差异添加到累积旋转值。
演示
var s = Snap(500, 500);
var thecircle = s.circle(250,250,100).attr({fill:'none',stroke:'red','stroke-width':'2'});
var pointer = s.rect(240,340,20,20);
var william = s.g(thecircle, pointer);
var hover1 = s.rect(240,290,20,20).attr({'value':'0'}).addClass('hovering');
var hover2 = hover1.clone().transform('r60,250,250').attr({'value':'60'}).addClass('hovering');
var hover3 = hover1.clone().transform('r120,250,250').attr({'value':'120'}).addClass('hovering');
var hover4 = hover1.clone().transform('r180,250,250').attr({'value':'180'}).addClass('hovering');
var hover5 = hover1.clone().transform('r240,250,250').attr({'value':'240'}).addClass('hovering');
var hover6 = hover1.clone().transform('r300,250,250').attr({'value':'300'}).addClass('hovering');
var $ = jQuery;
// What rotate currently is
var lastRotate = 0;
// Actual transform rotate accumulates up or down depending
// on which direction we have been going in.
var accumulatedRotation = 0;
$('.hovering').mouseenter(function(){
// Make sure 'rotate' is a number not a string
var rotate = parseInt($(this).attr('value'), 10);
// rotateAlt is the alternative version of rotate (either >360 or <0)
var rotateAlt = (lastRotate < 180) ? (rotate - 360) : (360 + rotate);
// Work out the diff value for each alt
var diffA = rotate - lastRotate;
var diffB = rotateAlt - lastRotate;
// Add the smaller diff to the accumulated rotation
if (Math.abs(diffA) < Math.abs(diffB))
accumulatedRotation += diffA;
else
accumulatedRotation += diffB;
william.animate({transform:'r'+accumulatedRotation+',250,250'},300,mina.ease);
// Remember the last value of 'rotate'
lastRotate = rotate;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
首先,抱歉主题名称。我真的不能用一句话准确地解释我想做什么。
那么!我要做的是一个圆,圆上有一个正方形,里面有6个"hoverable"个正方形。
这是我做的测试:
var s = Snap(500, 500);
var thecircle = s.circle(250,250,100).attr({fill:'none',stroke:'red','stroke-width':'2'});
var pointer = s.rect(240,340,20,20);
var william = s.g(thecircle, pointer);
var hover1 = s.rect(240,290,20,20).attr({'value':'0'}).addClass('hovering');
var hover2 = hover1.clone().transform('r60,250,250').attr({'value':'60'}).addClass('hovering');
var hover3 = hover1.clone().transform('r120,250,250').attr({'value':'120'}).addClass('hovering');
var hover4 = hover1.clone().transform('r180,250,250').attr({'value':'180'}).addClass('hovering');
var hover5 = hover1.clone().transform('r240,250,250').attr({'value':'240'}).addClass('hovering');
var hover6 = hover1.clone().transform('r300,250,250').attr({'value':'300'}).addClass('hovering');
var $ = jQuery;
$('.hovering').mouseenter(function(){
var rotate = $(this).attr('value');
william.animate({transform:'r'+rotate+',250,250'},300,mina.ease);
});
这是一个 fiddle 以便您可以检查动画的外观:JSfiddle
现在,看看将第 6 个方块(300 度)悬停然后将第 2 个方块(60 度)悬停时会发生什么。指针将在第 5、4 和 3 之前一直移动到第 2(移动 240 度)。
我想让我的指针走最快的路线到达目的地,在这个例子中,它是 420 度。 但是我不知道如何让它表现得那样,因为我不太擅长数学...
已更新
要解决这个问题,首先我们需要创建一个变量 prevRotate
- 初始设置为 0
- 要记录指针先前位置的值,那么我们需要处理四种特殊情况(1)以及正常情况如下所示:
当指针先前在底部方块上时(
rotate
值=0
),鼠标悬停在一个方块上旋转值大于180
,需要将指针逆时针移动-1 * (360 - rotate)
。然后使用回调函数,我们使用动画时间为 [=13= 的.animate()
函数将旋转度 立即 设置为原始rotate
值].当指针原本在
rotate
值大于180
的方块上时,悬停在下方方块上其旋转值为0
,将指针动画化为360
CW 方向,然后使用我们的回调我们将其重置为0
.当指针先前位于
rotate
值为300
的方块上时,鼠标悬停在方块上rotate
的值为60
,我们需要从300
到420
(300 + (360-300) + 60
),然后使用回调函数将旋转值重置为60
.当指针先前位于
rotate
值为60
的正方形时,我们需要将其设置为正方形60
=14=] 的300
,我们需要从60
动画到-60
然后立即再次使用回调函数将旋转设置为300
。
最后我们需要更新 prevRotate
的值以便进一步比较。
var $ = jQuery,
prevRotate = 0; // The variable used to store the previous location of the pointer.
$('.hovering').mouseenter(function(){
var rotate = $(this).attr('value');
// Special case 1, moving the pointer CCW following the short route.
if( prevRotate == 0){
var tempR = rotate;
rotate = rotate > 180 ? -1 * (360 - rotate) : rotate;
william.animate({transform:'r' +rotate+ ',250,250'},300,mina.ease, function(){
myCB(tempR);
});
}else{
// Normal case.
william.animate({transform:'r'+ rotate +',250,250'},300,mina.ease);
}
if(rotate == 0){
// Special Case 2, animating to 360 instead of 0, then to 0 immediately.
if(prevRotate > 180){
william.animate({transform:'r360,250,250'},300,mina.ease,function(){
myCB(0);
});
}
}else if(rotate == 60 && prevRotate == 300){
// Special Case 3, animating from 300 to 60 following the short route.
william.animate({transform:'r420,250,250'},300,mina.ease, function(){
myCB(60);
});
}else if(rotate == 300 && prevRotate == 60){
// Special Case 4, animating from 60 to 30 following short route.
william.animate({transform:'r-60,250,250'},300,mina.ease, function(){
myCB(300);
});
}
// Update the value of the pointer's previous location
prevRotate = $(this).attr('value');
});
// The Callback function to reset rotate values.
function myCB(theAngle){
william.animate({transform:'r' +theAngle+ ',250,250'},0);
}
(1) 请注意,您可以像这样将特殊情况 3 和 4 代码块合并为一个:
if((rotate == 60 || rotate == 300) && prevRotate == 360 - rotate){
// Define the destination angle depending on value of rotate
var newR = (rotate == 60) ? 420 : -60;
william.animate({transform:'r' +newR+ ',250,250'},300,mina.ease,function(){
myCB(prevRotate);
});
}
你只需要计算出两个可能方向中哪个方向的距离最短。然后将最小的差异添加到累积旋转值。
演示
var s = Snap(500, 500);
var thecircle = s.circle(250,250,100).attr({fill:'none',stroke:'red','stroke-width':'2'});
var pointer = s.rect(240,340,20,20);
var william = s.g(thecircle, pointer);
var hover1 = s.rect(240,290,20,20).attr({'value':'0'}).addClass('hovering');
var hover2 = hover1.clone().transform('r60,250,250').attr({'value':'60'}).addClass('hovering');
var hover3 = hover1.clone().transform('r120,250,250').attr({'value':'120'}).addClass('hovering');
var hover4 = hover1.clone().transform('r180,250,250').attr({'value':'180'}).addClass('hovering');
var hover5 = hover1.clone().transform('r240,250,250').attr({'value':'240'}).addClass('hovering');
var hover6 = hover1.clone().transform('r300,250,250').attr({'value':'300'}).addClass('hovering');
var $ = jQuery;
// What rotate currently is
var lastRotate = 0;
// Actual transform rotate accumulates up or down depending
// on which direction we have been going in.
var accumulatedRotation = 0;
$('.hovering').mouseenter(function(){
// Make sure 'rotate' is a number not a string
var rotate = parseInt($(this).attr('value'), 10);
// rotateAlt is the alternative version of rotate (either >360 or <0)
var rotateAlt = (lastRotate < 180) ? (rotate - 360) : (360 + rotate);
// Work out the diff value for each alt
var diffA = rotate - lastRotate;
var diffB = rotateAlt - lastRotate;
// Add the smaller diff to the accumulated rotation
if (Math.abs(diffA) < Math.abs(diffB))
accumulatedRotation += diffA;
else
accumulatedRotation += diffB;
william.animate({transform:'r'+accumulatedRotation+',250,250'},300,mina.ease);
// Remember the last value of 'rotate'
lastRotate = rotate;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>