基于滑块值的平滑动画

Posted

技术标签:

【中文标题】基于滑块值的平滑动画【英文标题】:Smooth animation based on slider value 【发布时间】:2013-10-08 04:01:06 【问题描述】:

我有一个基本的 html Slider 元素。我希望制作的内容很简单——当滑块位于一端时,会输出一张简单的笑脸。当它在另一端时,输出一张简单的悲伤脸。

我想要的关键是从动画的一侧到另一侧的平滑过渡 - 所以笑脸会经历冷漠和轻微快乐/轻微悲伤的不同阶段。

假设滑块输出了一个介于 1 到 10 之间的浮点数,对应于显示图像的“幸福度”。

您将如何解决这个问题?我试过搜索和谷歌搜索,但没有好的结果。可接受的所有技术 - 对如何存储图像/动画特别感兴趣。

【问题讨论】:

您可以像 Akismet 为他们的个人计划所做的那样做一些事情,即“akismet 对您有什么价值?” akismet.com/account/upgrade 处的滑块。他们只是拥有不同笑脸的图像,并在它们之间切换akismet.com/img/ab/smiley.png 【参考方案1】:

如果您可以在 SVG 中绘制脸部,您可以使用 Raphael 之类的东西。例如,如果您要保持相同的圆脸并仅变形嘴巴。这将在形状之间设置动画。不太确定这是否是您的意思。这是我的 2 秒可怕的嘴巴路径。

var paper = Raphael( "canvas_container",400,400);

paper.circle(280, 210, 150);
// create the 2 paths to animate between in some app like inkscape
var pathStr1 = "m385,255l-197,-3l40,57l88,1l35,0l34,-55z", 
pathStr2 =  "m207,268l162,-1l-33,-45l-41,-2l-46,-1l-32,20l-10,29z"; 

var path = paper.path(pathStr1).attr(fill: "yellow", "stroke-width": 3); 

setTimeout(function()path.animate(path: pathStr2, 3000, "linear");, 1000);  

http://jsfiddle.net/YUhHw/1/ 有一个小提琴,http://cancerbero.mbarreneche.com/raphaeltut/#sec-animation 有更好的示例(上面的代码基于部分)的教程,http://raphaeljs.com/animation.html 有很好的示例我猜你需要更改 setTimeout 以对应于你的滑块。

【讨论】:

这也很酷。我担心使用这些路径创建设计的数学计算会太多,但看起来真的很复杂。有没有办法“绘制”图像,并让它为你绘制要转换的线的 pathStr? 是的,如果你使用类似 inkscape inkscape.org 的东西,你可以创建 svg 并在它们之间制作动画(你可能想要创建单独的头部,然后在 pathStr1 和 pathStr2 之间制作动画的两个嘴) .您可能需要查看 svg 标记本身,这样才有意义。要快速进行基本操作,您可以转到svg-edit.googlecode.com/svn-history/r1771/trunk/editor/… 然后画一些东西,然后单击 svg 按钮,它会显示标记以感受它。【参考方案2】:

您可以使用 CSS 的 transform: rotateX 来做您想做的事。在我的版本中,我还使用了 HTML5 的 inputtype="range",但如果您想影响旧浏览器,您可以使用相同的方法和更全局的滑块。该演示涉及使用两张图像,一张用于面部和背景,一张用于嘴唇,但如果您喜欢该技术,您可以以同样的方式将其应用于纯 CSS。只需确保在 javascript 中包含所需的所有浏览器前缀

Live Demo Here

/* HTML */
<div id='slimey'>
    <div id='lips'></div>
</div>
<input id="smileSlide" type="range" onchange="changeSmile(this)" value="0" />

/* Javascript */
var lips = document.getElementById('lips');
function changeSmile(slider) 
    var sliderVal = slider.value,
        rotateDegree = - sliderVal * 1.8;
    lips.style.webkitTransform = "rotateX(" + rotateDegree + "deg)";
    lips.style.transform = "rotateX(" + rotateDegree + "deg)";


/* CSS */
#slimey 
    margin:auto;
    background:url(http://i.imgur.com/LGQMhc3.jpg);
    background-size: 100% 100%;
    height:100px;
    width:100px;
    position:relative;

#lips 
    width:50px;
    height:20px;
    position:absolute;
    top:calc(70% - 10px);
    left:calc(50% - 25px);
    background:url(http://i.imgur.com/20EmUM7.gif);
    background-size: 100% 100%;
    -webkit-transform:rotateX(0deg);
    transform:rotateX(0deg);

#smileSlide 
    width:100px;
    position:absolute;
    left:calc(50% - 50px);     

灵感来自Marco Barria's(这家伙有一些很棒的项目)single element flying bird

如果您想让中间状态更明显,您可以在中间范围like this demo does 中切换一行的显示。像这个答案的其余部分一样,它只是一个近似的解决方案,但我认为它很好地展示了这项技术。如果你想获得 super 的幻想,你甚至可以为线条添加淡入/淡出,让它看起来更平滑一点

【讨论】:

哦,这真的很酷。我很喜欢。感谢分享,我真的很感激。 同意,这是一个非常巧妙的方法。 酷。我不能使用calc(),所以我摆弄了它:jsfiddle.net/UV7gV/1(也没有图像):D【参考方案3】:

我使用纯 css 和 js 更改了 Zeaklous 的答案(没有任何图像或旋转) http://jsfiddle.net/sijav/PVvc4/3/

<!--HTML-->
<div id='slimey'>
    <div id='leye' class='eye'></div>
    <div id='reye' class='eye'></div>
    <div id='lips'></div>
</div>
<input id="smileSlide" type="range" onchange="changeSmile(this)" value="0" />

//Java Script
var lips = document.getElementById('lips');
function changeSmile(slider) 
    var lh = lips.style.height, slide=0;
    if ((50 - slider.value) > 0)
        slide = (50 - slider.value);
        lips.style.borderTop = "2px black solid";
        lips.style.borderBottom = "none";
    
    else 
        slide = (slider.value - 50);
        lips.style.borderBottom = "2px black solid";
        lips.style.borderTop = "none";
    
    lips.style.height = slide * 0.4 + "px" ;
    lips.style.top = "calc(70% + " + (- slide) * 0.2 + "px" ;


/**CSS**/
#leye
    left:25%;

#reye
    right:25%;

.eye
    position:absolute;
    background:black;
    border-radius:100%;
    height:15px;
    width:15px;
    top:20px;

#slimey 
    margin:auto;
    background:Yellow;
    border-radius:100%;
    height:100px;
    width:100px;
    position:relative;

#lips 
    width:50px;
    height:20px;
    position:absolute;
    top:calc(70% - 10px);
    left:calc(50% - 25px);
    background:transparent;
    border-top:2px black solid;
    -webkit-transform:rotateX(0deg);
    border-radius:100%;
    transform:rotateX(0deg);

#smileSlide 
    width:100px;
    position:absolute;
    left:calc(50% - 50px);     

编辑:嘴唇在此处移动的细微差别http://jsfiddle.net/sijav/PVvc4/4/

【讨论】:

【参考方案4】:

只需使用一个没有嘴巴的 png 脸,以及几个基于 Javascript 滑块位置切换的补间嘴巴。将文件存储在数组中,并从定时函数调用它们以检查面部位置。简单轻便。

var mouthArray = new Array('frown','half_frown','half_smile','smile');
var face       = document.getElementById('face');
var faceLoc    = parseInt(face.style.left);
function changeMouth() 
 if(faceLoc<10)
  theMouth.setAttribute('src',mouthArray[0]);
 if(faceLoc>10,faceLoc<=19)
  theMouth.setAttribute('src',mouthArray[1]);
 if(faceLoc>20,faceLoc<=29)
  theMouth.setAttribute('src',mouthArray[2]);
 if(faceLoc>30,faceLoc<40)
  theMouth.setAttribute('src',mouthArray[3]); 

如果对滑块的长度给予足够的迭代,那么沿着这些思路,应该会给你一个体面的“平滑”效果。

【讨论】:

【参考方案5】:

为了好玩,我在午餐时用纯 CSS(没有图像或 JavaScript)编写了一个纯 Webkit 的小版本——here's a demo。我不一定推荐这种方法,但我忍不住试一试!


这是一个非常简单的方法。我使用了一组单选按钮而不是滑块,它允许您使用 :checked 伪类来根据所选值更改嘴巴的颜色和形状。仅使用heightborder-radius 描述嘴形。例如:

#feel-0:checked ~ #mouth 
    border-radius: 30px 30px 0 0;
    height: 20px;
    margin-top: -5px;

说明文本只是所选单选按钮的标签字段。最初所有标签都是隐藏的,但是一旦选中一个字段,相邻的标签就会变得可见:

#happiness input:checked + label 
    visibility: visible;

您可以使用箭头键更改选择的字段(视觉上向左或向右移动滑块) - 这是单选组的内置行为。

通过一些工作,您可以调整它以使滑块在非 WebKit 浏览器中看起来更好;但是,在某些较旧的浏览器中它可能会出现问题,并且您无法向左或向右拖动滑块。对于生产,我会使用 JavaScript 滑块(例如,许多 可用的 jQuery 选项之一)并将 CSS 伪类魔法换成少量 JS 和少数类。

【讨论】:

以上是关于基于滑块值的平滑动画的主要内容,如果未能解决你的问题,请参考以下文章

更改 jQuery UI 滑块值选项时动画滑块句柄?

显示多个滑块值的 UILabel

WPF - 将滑块值数据绑定到 StoryBoard?

iOS,在滑块值 n 处触发一次 UIViewAnimation?

如何以编程方式创建默认滑块值?

如何在NetLogo中创建2个滑块值不能超过定义值的条件?