CSS过渡无法使用javascript正确更新

时间:2018-07-21 16:35:23

标签: javascript html css svg css-transitions

我想创建一个简单的svg动画库。我希望能够在javascript中定义关键帧,然后该库将使用stroke-dasharray和dashoffset属性上的过渡为svg路径设置动画。奇怪的是,它第一次正常工作。再次触发时,仅#path1会正确设置动画。我尝试在chrome中调试(也在chrome中测试),当我使用调试器时,它可以工作。我检查了每个变量,它们都是正确的。

出于测试目的,我将添加所有文件和一个指向jquery的外部链接。

var JAnim = {

    parse_distance: function(val, total_distance){

        // val is already a number
        if(typeof val == "number"){

            return val;
        }
        var parsed = parseInt(val, 10);

        // invalid value given
        if(isNaN(parsed)){

            throw "Value " + val + " is not a valid number!";
        }

        // number given in percent
        if(val[-1] == "%"){

            return (parsed / 100) * total_distance;
        }

        // number given as a string
        return parsed;
    },

    set: function(target, options) {
        
        // check if values were supplied
        if(options == undefined || options == null){

            throw "No options specified!";
        }

        if(options.begin == undefined || options.begin == null){

            throw "Missing mandatory begin attribute!";
        }

        if(options.end == undefined || options.end == null){

            throw "Missing mandatory end attribute!";
        }
        // --------------------------------------------------------

        // query target elements
        var elements = document.querySelectorAll(target);

        for(var i = 0; i < elements.length; i++){

            // check if valid element is selected
            if(elements[i].tagName != "path"){

                throw "Unsupported element: \"" + elements[i].tagName + "\" !";
            }

            var total_distance = elements[i].getTotalLength();

            var begin = this.parse_distance(options.begin, total_distance);
            var end   = this.parse_distance(options.end, total_distance);

            // sanity check
            if(begin > end) {

                throw "Begin value greater than end!";
            }

            var distance_to_show = end - begin;

            // stroke-dasharray formula: distance_to_show remaining_distance_to_hide
            // stroke-dashoffset uses negative begin value, because positive values offset from the back
            elements[i].style["stroke-dasharray"] = distance_to_show.toString() + " " + (total_distance - distance_to_show).toString();
            elements[i].style["stroke-dashoffset"] = (-begin).toString();
        }
    },

    animate: function(target, animation){

        // check if proper values were supplied 

        if(animation == undefined || animation == null){

            throw "No animation specified!";
        }

        if(animation.duration == undefined || animation.duration == null){

            throw "Missing mandatory duration attribute!";
        }

        if(typeof animation.duration != "number"){

            throw "Invalid value given from duration!";
        }

        if(document.querySelectorAll(target).length == 0){
            // no items were selected
            return;
        }

        // get percentages and sort them
        var keys = Object.keys(animation.keyframes);
        keys.sort(function(a,b) { return parseInt(a) - parseInt(b); });

        this.clear_transition(target);

        // set initial state
        var i = 0;
        if(keys[i] == "0%"){

            this.set(target, {begin: animation.keyframes[keys[i]].begin, end: animation.keyframes[keys[i]].end });
            i++;
        }

        // calculate time
        var time = (parseInt(keys[i]) / 100) * animation.duration;

        this.set_transition(target, "stroke-dasharray "  + time + "ms " + animation.keyframes[keys[i]].timing + ", " +
                                    "stroke-dashoffset " + time + "ms " + animation.keyframes[keys[i]].timing);


        this.set(target, {begin: animation.keyframes[keys[i]].begin, end: animation.keyframes[keys[i]].end });
        i++;
    },

    clear_transition: function(target){

        var elements = document.querySelectorAll(target);
    
        for(var i = 0; i < elements.length; i++){
            
            elements[i].style["transition-property"] = "none";
        }
    }, 

    set_transition: function(target, trans){

        var elements = document.querySelectorAll(target);
    
        for(var i = 0; i < elements.length; i++){
            
            elements[i].style.transition = trans;
        }
    }
}

// -------------------------------------- lib ends here ------- the next part is just using it

var menu_anim_id = null;

function animate_menu(){

    var anim = {

        duration: 2500,
        keyframes: {

            "0%": {

                begin: 0,
                end: 80
            },
            "50%": {

                begin: 80,
                end: 81,
                timing: "ease-in"
            },
            "100%": {

                begin: 95,
                end: 167,
                timing: "ease-out"
            }
        }
    };

    JAnim.animate("#path1, #path3", anim);

    /*
    anim = {
        
        duration: 500,
        on_finish: null,
        keyframes: {
            
            "0%": {
                
                begin: 0,
                end: 80
            },
            "100%": {
                
                begin: 40,
                end: 40,
                timing: "ease-out"
            }
        }
    };
    JAnim.animate("#path2", anim);
    */
}

function keypressed(e) {

    if(e.key == "Enter"){

        JAnim.set("#path1, #path3", {begin: 0, end: 80});
    }

    if(e.key == " ") {

        JAnim.set("#path1, #path3", {begin: 20, end: 30});
    }
}

function setup(){

    JAnim.set("#path1, #path3", {begin: 0, end: 80});
    $("#btn").click(animate_menu);
    
    $(document).keypress(keypressed);
}

$(document).ready(setup);
* {

    margin: 0;
}

#menu path {

    fill: none;
    stroke: black;
    stroke-width: 15px;
    stroke-linecap: round;
    stroke-linejoin: round;
}

#btn {

    width: 70pt;
    height: 70pt;
    position: fixed;
    top: calc(50% - 70pt);
    left: calc(50% - 70pt);
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Title</title>
    <link rel="stylesheet" type="text/css" href="res/css/main.css" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
    <div id="btn">
        <svg id="menu" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
            
            <path id="path1" d="m10,20 l80,0 l-70,50"/>
            <path id="path2" d="m10,50 l80,0"/>
            <path id="path3" d="m10,80 l80,0 l-70,-50"/>
            
        </svg>
    </div>
</body>
</html>

我对webdev还是很陌生,不确定这是否是正确的方法。问题最有可能出现在动画功能中。对我来说,过渡似乎没有正确更新。如果您是第一次运行动画,那么请按空格键使其进入“测试状态”,然后再次触发动画。结果是#path1捕捉到正确的状态并按照定义进行动画处理,但是#path3只是异常地过渡到了该状态。同时按回车键将其恢复为原始状态,然后再次运行。请随时询问更多信息,谢谢。

0 个答案:

没有答案