简体   繁体   中英

Why doesn't CSS transition get applied?

I've built a small stacked bar visual just using floated divs that underneath is bound to some data using knockout . What I want to be able to do is to animate changes in the size of these stacks when the data changes.

I've managed to do this in the general case, so of the 4 bars that I've got, 3 of them transition correctly. The problem is my final bar seems to ignore the transition and instantly re-sizes and I can't understand why. Here's a picture of the before/during/after states:

在此输入图像描述

The way that I've defined this transition is simply via css

-webkit-transition: width 1s;
transition: width 1s;

The width of the bars is a computed value, calculating the percentage of items, so each bar should have it's width defined as a percentage. Although the red bar is calculated differently to the other 3 bars, I don't see why that should affect the transition.

What I find quite strange, is that if I modify the width through the developer console for example, then the bar does correctly animate. I'm wondering if anyone can suggest why this might be the case?

 var vm = (function generateModel() { var data = { name: "Sign-off", id: "XX", values: [{ text: "Signed-off", count: 150, color: "#5fb5cc" }, { text: "Submitted", count: 90, color: "#75d181" }, { text: "Not Submitted", count: 75, color: "#f8a25b" } ], aggregates: { count: 650 } }; // Create a view model directly from the data which we will update var vm = ko.mapping.fromJS(data); // Add a computed value to calculate percentage vm.values().forEach(function (d) { d.percentage = ko.computed(function () { return d.count() / vm.aggregates.count() * 100; }); }); // Create a vm.allValues = ko.computed(function() { var values = []; var count = 0; var total = vm.aggregates.count(); debugger; // Add each of these results into those that will be returned vm.values().forEach(function(d) { values.push(d); count += d.count(); }); // Create an other category for everything else values.push({ text: ko.observable("Other"), count: ko.observable(total - count), percentage: ko.observable((total - count) / total * 100), color: ko.observable("#ff0000") }); return values; }); return vm; })(); ko.applyBindings(vm); setTimeout(function() { vm.values()[0].count(90); vm.values()[1].count(40); vm.values()[2].count(35); vm.aggregates.count(3550); }, 3000); 
 body { background: rgb(40, 40, 40); } .spacer { height: 230px; } .cards { float: right; } /* Small Card */ .card { margin-bottom: 3px; background: white; border-radius: 3px; width:398px; float: right; clear: both; min-height: 100px; padding: 10px 5px 15px 5px; font-family:'Open Sans', Arial, sans-serif; } .title { color: rgb(105, 161, 36); font-size: 16px; } .states { padding-top: 10px; } .state { font-size: 12px; color: rgb(67, 88, 98); padding: 0px 5px 2px 5px; clear: both; } .circle { width: 10px; height: 10px; border-radius: 50%; float: left; margin: 1px 5px 5px 0px; } .value { float: right; } .graph { padding: 10px 5px 0px 5px; } .bar { float: left; height: 10px; -webkit-transition: width 10s; transition: width 10s; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <script src="http://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script> <div class="card"> <div class="content"> <div class="graph" data-bind="foreach: allValues"> <div class="bar" data-bind="style: { background: color, width: percentage() + '%' }"/> </div> </div> </div> 

As the first 3 are based on object references that don't change, knockout is preserving the actual <div> that's been rendered.

For the final bar, each time allValues is evaluated, it's pushing a brand new object into the returned array. I would assume that since knockout sees that as a new object, it re-renders the div from scratch, rather than updating existing bindings.

You'll need to rework your model slightly to hold an actual object for that final value so that you can then update the observables on it in the same way.

Here's a fixed version using a static object for the "other" value:

 var vm = (function generateModel() { var data = { name: "Sign-off", id: "XX", values: [{ text: "Signed-off", count: 150, color: "#5fb5cc" }, { text: "Submitted", count: 90, color: "#75d181" }, { text: "Not Submitted", count: 75, color: "#f8a25b" } ], aggregates: { count: 650 } }; // Create a view model directly from the data which we will update var vm = ko.mapping.fromJS(data); // Add a computed value to calculate percentage vm.values().forEach(function (d) { d.percentage = ko.computed(function () { return d.count() / vm.aggregates.count() * 100; }); }); //Create a static "others" object vm.other = { text: ko.observable("Other"), count: ko.computed(function() { var total = vm.aggregates.count(); var count = 0; vm.values().forEach(function(d) { count += d.count(); }); return total - count; }), percentage: ko.computed(function(d, b) { var total = vm.aggregates.count(); var count = 0; vm.values().forEach(function(d) { count += d.count(); }); return (total - count) / total * 100; }), color: ko.observable("#ff0000") }; // Create a vm.allValues = ko.computed(function() { var values = []; var count = 0; var total = vm.aggregates.count(); debugger; // Add each of these results into those that will be returned vm.values().forEach(function(d) { values.push(d); count += d.count(); }); // and push static object in instead of creating a new one values.push(vm.other); return values; }); return vm; })(); ko.applyBindings(vm); setTimeout(function() { vm.values()[0].count(90); vm.values()[1].count(40); vm.values()[2].count(35); vm.aggregates.count(3550); }, 3000); 
 body { background: rgb(40, 40, 40); } .spacer { height: 230px; } .cards { float: right; } /* Small Card */ .card { margin-bottom: 3px; background: white; border-radius: 3px; width:398px; float: right; clear: both; min-height: 100px; padding: 10px 5px 15px 5px; font-family:'Open Sans', Arial, sans-serif; } .title { color: rgb(105, 161, 36); font-size: 16px; } .states { padding-top: 10px; } .state { font-size: 12px; color: rgb(67, 88, 98); padding: 0px 5px 2px 5px; clear: both; } .circle { width: 10px; height: 10px; border-radius: 50%; float: left; margin: 1px 5px 5px 0px; } .value { float: right; } .graph { padding: 10px 5px 0px 5px; } .bar { float: left; height: 10px; -webkit-transition: width 10s; transition: width 10s; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <script src="http://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script> <div class="card"> <div class="content"> <div class="graph" data-bind="foreach: allValues"> <div class="bar" data-bind="style: { background: color, width: percentage() + '%' }"/> </div> </div> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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