简体   繁体   English

同时使用scaleX和translationX(VelocityJS)

[英]Using scaleX and translationX at the same time (VelocityJS)

I have a bar that is filled from a certain percentage to another percentage (0% - 50%). 我有一个酒吧,从某个百分比填充到另一个百分比(0%-50%)。 I want to smoothly animate this towards a new range (25% - 55%). 我想使动画朝着新的范围(25%-55%)移动。 This means both the width and the location of the bar will need to be changed. 这意味着条的宽度和位置都需要更改。 I'm having some trouble doing both of these smoothly at the same time. 我在同时顺利完成这两项操作时遇到了一些麻烦。

After some research I found I needed to use scaleX to smoothly animate the width and translateX to smoothly animate the location (where translateX is also affected by the scale). 经过一番研究,我发现我需要使用scaleX顺利动画的宽度和translateX顺畅动画的位置(其中translateX也受规模)。 The problem that occurs now is that the bar will overstep it's desired percentage (55%) and then move back as shown in the snippet below. 现在出现的问题是,条形图将超出其所需的百分比(55%),然后如下面的代码片段所示向后移动。

 /* Button function to restart. */ const restart = () => { animate(); } const animate = () => { /* Reset the bar to its starting position. (from 0% - 50%) */ Velocity(document.getElementById('movingBar'), { scaleX: 0.5, translateX: 0 }, { duration: 0, easing: [0, 0, 1, 1] }); /* Move the bar to its final position. (from 25% - 55%). */ /* Split into two velocity calls so that they can have a seperate duration/easing if needed. */ Velocity(document.getElementById('movingBar'), { scaleX: 0.30 }, { duration: 1000, easing: [0, 0, 1, 1], queue: false }); Velocity(document.getElementById('movingBar'), { translateX: (25 / 0.30) + '%' }, { duration: 1000, easing: [0, 0, 1, 1], queue: false }); }; /* Start animation on run. */ animate(); 
 #root { width: 700px; height: 100%; } #container { width: 100%; height: 90px; background-color: #000000; } .bar { width: 100%; height: 30px; transform: scaleX(0.5); transform-origin: left; background-color: #FF0000; } #description { display: flex; } .percentage { display: flex; justify-content: flex-end; width: 10%; height: 20px; text-align: right; } .odd { background-color: #DDDDDD; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script> <div id='root' style='width: 100%; height: 100%'> <div id='container'> <div class="bar" style="background-color: #00FF00;"></div> <div id='movingBar' class="bar"></div> <div class="bar" style="background-color: #00FF00; transform: scaleX(0.30) translateX(calc(25 / 0.30 * 1%))"></div> </div> <div id='description'> <div class="percentage even">10%</div> <div class="percentage odd">20%</div> <div class="percentage even">30%</div> <div class="percentage odd">40%</div> <div class="percentage even">50%</div> <div class="percentage odd">60%</div> <div class="percentage even">70%</div> <div class="percentage odd">80%</div> <div class="percentage even">90%</div> <div class="percentage odd">100%</div> </div> <button onClick="restart()">restart</button> </div> 

The example shows the starting position in the top green bar, and the desired position it should animate to in the bottom green bar. 该示例在顶部绿色栏中显示了起始位置,并在底部绿色栏中显示了应设置为动画的所需位置。 The middle red bar is the bar that should animate from the starting position to the desired position. 中间的红色条是应该从开始位置到所需位置进行动画处理的条。 As you can see the red bar reaches the desired result eventually but not before going over 55% for a bit. 如您所见,红色条最终达到了预期的结果,但在超过55%之前还没有达到。 I'm using VelocityJS to animate at the moment. 目前,我正在使用VelocityJS进行动画处理。

Any idea what I'm doing wrong or how I would go about animating this? 知道我做错了什么或如何制作动画吗? Is there some calculation I need to do to the duration/easing to correct whatever is going wrong? 我需要对持续时间/放松进行一些计算以纠正出现问题的地方吗?

The issue is related to how the interpolation of values is done. 问题与值的插值方式有关。 It would be a hard work to make sure to have a global linear transformation using scaleX and translateX because you cannot control the interpolation of values and the browser will do this for you. 确保使用scaleX和translateX进行全局线性变换将是一项艰巨的工作,因为您无法控制值的插值,并且浏览器将为您完成此操作。 so either you do a complex calculation of the duration/easing to find a perfect result or you consider another kind of animation. 因此,您可以对持续时间/缓和进行复杂的计算以找到理想的结果,或者考虑使用另一种动画。

For such situation I would consider clip-path even if the support isn't optimal but it will be easier to handle since you have only one property to animate and you don't need any complex calculation as you simply have to use the percentage of the graph. 在这种情况下,即使支持不是最佳选择,我也会考虑clip-path但是由于您只需要设置一个动画属性,并且不需要任何复杂的计算,因为您只需要使用百分比,就可以轻松处理clip-path 。图。

Here is a simplified example: 这是一个简化的示例:

 body { background:#000; } .box { height:50px; background:red; clip-path:polygon(10% 100%,10% 0, 40% 0,40% 100%); /*from [10% 40%]*/ transition:1s all; } body:hover .box { clip-path:polygon(50% 100%,50% 0, 60% 0,60% 100%); /*to [50% 60%]*/ } 
 <div class="box"> </div> 

I started with the math while trying to find an answer and got this for translation easing which is almost perfect: [1/3, 0.2, 2/3, 1 - (8/15)]; 我从数学开始,试图寻找答案,并且得到了几乎完美的翻译缓和: [1/3, 0.2, 2/3, 1 - (8/15)];

I calculated those by created a formula for what the translation path should look like 25x / (-0.2x + 0.5) . 我通过为转换路径看起来像25x / (-0.2x + 0.5)的公式创建了一个公式。 I then divided it by 83.333333 to get the desired translation formula in a [0, 1] window. 然后,将其除以83.333333以在[0,1]窗口中获得所需的转换公式。 I then used the formula of (25x / (-0.2x + 0.5)) / 83.333333 to calculate the cubic-bezier points which I used above. 然后,我使用(25x / (-0.2x + 0.5)) / 83.333333来计算上面使用的三次(25x / (-0.2x + 0.5)) / 83.333333点。 Note that I do 1-C2y for the 4th point, not sure why but otherwise it wouldnt work. 请注意,我对第4点做1-C2y,不知道为什么,否则不起作用。

NOTE: This worked for the original problem above but fails to work when the scale changes from anything other than 0.5 - 0.3. 注意:这适用于上面的原始问题,但是当比例从0.5-0.3以外的任何其他值更改时,此方法将无法工作。 I'm still figuring out why. 我还在弄清楚为什么。

 /* Button function to restart. */ const restart = () => { animate(); } const desiredX = 0.5; let desiredYScale = 0; let desiredYTranslation = 0; const animate = () => { const barMax = 100; const scaleStart = 0.5; const scaleEnd = 0.4; const offsetStart = 0; const offsetEnd = 10; const translationStart = 100 / barMax * offsetStart / scaleStart; const translationEnd = 100 / barMax * offsetEnd / scaleEnd; const dataS = {}; const dataT = {}; const F = 0.5; const scaleFormula = ((-scaleStart + scaleEnd) * F + scaleStart); //console.log("scale formula: ", scaleFormula); const translationPath = (offsetEnd * F) / scaleFormula; const diffPath = translationPath - (offsetEnd / scaleEnd * F); const diffFormulaA = - (diffPath / (F * F)); const diffFormula = (diffFormulaA/diffPath) * (F - 0.5) * (F - 0.5) + 1 const diffA = diffFormulaA / diffPath; const cX = 0.5; const cY = 0.5 * Math.abs(diffA); const cAx = 2/3 * cX; const cAy = 2/3 * cY; const cBx = 2/3 * cX + 1/3 * 1; const cBy = 2/3 * cY + 1/3 * 1; const multiplicant = 0.5; const realCAX = cAx / cBy * multiplicant; const realCAY = cAy / cBy * multiplicant; const realCBX = 1 - (cBx / cBy * multiplicant); const realCBY = cBy / cBy * multiplicant; console.log("realCAX: ", realCAX); console.log("realCAY: ", realCAY); console.log("realCBX: ", realCBX); console.log("realCBY: ", realCBY); const linearEasing = [0, 0, 1, 1]; //const one = 0.5 + (scaleEnd / 4); //const two = 0.525 - (scaleStart - scaleEnd); //const one = 0.40 + 0.025 / (0.5 - (scaleStart - scaleEnd)); //console.log("One: ", one, (scaleStart - scaleEnd)); //const one = 0.5; //const one = 0.535; //const one = 0.5; const one = 0.5; const two = 0.1; //const two = 0.125; //const translationEasing = [0.33, 10, 0.66, 16]; //const translationEasing = [1/3, 0.2, 2/3, 1-(8/15)]; //const translationEasing = [1/3, 1/15, 2/3, 1-0.4]; //const translationEasing = [0.24, 0.06666, 0.85, 0.1]; //const translationEasing = [0.33, 1.33, 0.66, 1.66]; //const translationEasing = [0.2, 0.8, 0.4, 1]; //const translationEasing = [0.1, 0.4, 1-0.2, 0.5]; //const translationEasing = [realCAX, realCAY, realCBX, realCBY]; //const translationEasing = [1/3, 0.0833333, 2/3, 0.42]; const translationEasing = [one, two, 1-two, 1-one]; //const translationEasing = [0, 0, 1, 1];5 /* Reset the bar to its starting position. (from 0% - 50%) */ Velocity(document.getElementById('movingBar'), { scaleX: scaleStart, translateX: translationStart + '%' }, { duration: 0, easing: linearEasing }); /* Move the bar to its final position. (from 25% - 55%). */ /* Split into two velocity calls so that they can have a seperate duration/easing if needed. */ Velocity(document.getElementById('movingBar'), { scaleX: scaleEnd }, { duration: 1000, easing: linearEasing, queue: false, progress: function(elements, complete, remaining, start, tweenValue) { dataS[complete] = scaleStart + ((scaleEnd - scaleStart) * complete); } }); Velocity(document.getElementById('movingBar'), { translateX: translationEnd + '%', tween: translationEnd }, { duration: 1000, easing: translationEasing, queue: false, progress: function(elements, complete, remaining, start, tweenValue) { dataT[complete] = translationStart + ((translationEnd - translationStart) * complete); console.log("TWEEN", complete, tweenValue); }, complete: function() { //console.log("DONE!"); //console.log("SCALE:"); //if (desiredX in dataS) { //console.log('Scale[0.5]: ', dataS[desiredX], ', Translation[0.5]: ', dataT[desiredX]); //desiredYScale = dataS[desiredX]; //desiredYTranslation = dataT[desiredX]; //} else { //animate(); //} for (const key in dataS) { if (dataS.hasOwnProperty(key)) { //console.log('', key, ': ', dataS[key]); } } //console.log("TRANSLATION:"); for (const key in dataT) { if (dataT.hasOwnProperty(key)) { //console.log('', key, ': ', dataT[key]); } } } }); }; /* Start animation on run. */ animate(); 
 #root { width: 700px; height: 100%; } #container { width: 100%; height: 90px; background-color: #000000; } .bar { width: 100%; height: 30px; transform: scaleX(0.5) transform (calc(20 / 0.5 * 1%)); transform-origin: left; background-color: #FF0000; } #description { display: flex; } .percentage { display: flex; justify-content: flex-end; width: 10%; height: 20px; text-align: right; } .odd { background-color: #DDDDDD; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.2/velocity.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script> <div id='root' style='width: 100%; height: 100%'> <div id='container'> <div class="bar" style="background-color: #00FF00; transform: scaleX(0.5) translateX(calc(0 / 0.5 * 1%))"></div> <div id='movingBar' class="bar"></div> <div class="bar" style="background-color: #00FF00; transform: scaleX(0.4) translateX(calc(10 / 0.4 * 1%))"></div> </div> <div id='description'> <div class="percentage even">10%</div> <div class="percentage odd">20%</div> <div class="percentage even">30%</div> <div class="percentage odd">40%</div> <div class="percentage even">50%</div> <div class="percentage odd">60%</div> <div class="percentage even">70%</div> <div class="percentage odd">80%</div> <div class="percentage even">90%</div> <div class="percentage odd">100%</div> </div> <button onClick="restart()">restart</button> </div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM