Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | |
|
pfeldman
2015/09/19 00:17:40
Could you split this into the move and refactoring
| |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * @constructor | |
| 7 * @param {!WebInspector.AnimationModel.Animation} animation | |
| 8 * @param {!WebInspector.AnimationTimeline} timeline | |
| 9 * @param {!Element} parentElement | |
| 10 */ | |
| 11 WebInspector.AnimationUI = function(animation, timeline, parentElement) { | |
| 12 this._animation = animation; | |
| 13 this._timeline = timeline; | |
| 14 this._parentElement = parentElement; | |
| 15 | |
| 16 if (this._animation.source().keyframesRule()) | |
| 17 this._keyframes = this._animation.source().keyframesRule().keyframes(); | |
| 18 | |
| 19 this._nameElement = parentElement.createChild("div", "animation-name"); | |
| 20 this._nameElement.textContent = this._animation.name(); | |
| 21 | |
| 22 this._svg = parentElement.createSVGChild("svg", "animation-ui"); | |
| 23 this._svg.setAttribute("height", WebInspector.AnimationUI.Options.AnimationS VGHeight); | |
| 24 this._svg.style.marginLeft = "-" + WebInspector.AnimationUI.Options.Animatio nMargin + "px"; | |
| 25 this._svg.addEventListener("mousedown", this._mouseDown.bind(this, WebInspec tor.AnimationUI.MouseEvents.AnimationDrag, null)); | |
| 26 this._activeIntervalGroup = this._svg.createSVGChild("g"); | |
| 27 | |
| 28 /** @type {!Array.<{group: ?Element, animationLine: ?Element, keyframePoints : !Object.<number, !Element>, keyframeRender: !Object.<number, !Element>}>} */ | |
| 29 this._cachedElements = []; | |
| 30 | |
| 31 this._movementInMs = 0; | |
| 32 this._color = WebInspector.AnimationUI.Color(this._animation); | |
| 33 } | |
| 34 | |
| 35 /** | |
| 36 * @enum {string} | |
| 37 */ | |
| 38 WebInspector.AnimationUI.MouseEvents = { | |
| 39 AnimationDrag: "AnimationDrag", | |
| 40 KeyframeMove: "KeyframeMove", | |
| 41 StartEndpointMove: "StartEndpointMove", | |
| 42 FinishEndpointMove: "FinishEndpointMove" | |
| 43 } | |
| 44 | |
| 45 WebInspector.AnimationUI.prototype = { | |
| 46 /** | |
| 47 * @return {!WebInspector.AnimationModel.Animation} | |
| 48 */ | |
| 49 animation: function() | |
| 50 { | |
| 51 return this._animation; | |
| 52 }, | |
| 53 | |
| 54 /** | |
| 55 * @param {?WebInspector.DOMNode} node | |
| 56 */ | |
| 57 setNode: function(node) | |
| 58 { | |
| 59 this._node = node; | |
| 60 }, | |
| 61 | |
| 62 /** | |
| 63 * @param {!Element} parentElement | |
| 64 * @param {string} className | |
| 65 */ | |
| 66 _createLine: function(parentElement, className) | |
| 67 { | |
| 68 var line = parentElement.createSVGChild("line", className); | |
| 69 line.setAttribute("x1", WebInspector.AnimationUI.Options.AnimationMargin ); | |
| 70 line.setAttribute("y1", WebInspector.AnimationUI.Options.AnimationHeight ); | |
| 71 line.setAttribute("y2", WebInspector.AnimationUI.Options.AnimationHeight ); | |
| 72 line.style.stroke = this._color; | |
| 73 return line; | |
| 74 }, | |
| 75 | |
| 76 /** | |
| 77 * @param {number} iteration | |
| 78 * @param {!Element} parentElement | |
| 79 */ | |
| 80 _drawAnimationLine: function(iteration, parentElement) | |
| 81 { | |
| 82 var cache = this._cachedElements[iteration]; | |
| 83 if (!cache.animationLine) | |
| 84 cache.animationLine = this._createLine(parentElement, "animation-lin e"); | |
| 85 cache.animationLine.setAttribute("x2", (this._duration() * this._timelin e.pixelMsRatio() + WebInspector.AnimationUI.Options.AnimationMargin).toFixed(2)) ; | |
| 86 }, | |
| 87 | |
| 88 /** | |
| 89 * @param {!Element} parentElement | |
| 90 */ | |
| 91 _drawDelayLine: function(parentElement) | |
| 92 { | |
| 93 if (!this._delayLine) { | |
| 94 this._delayLine = this._createLine(parentElement, "animation-delay-l ine"); | |
| 95 this._endDelayLine = this._createLine(parentElement, "animation-dela y-line"); | |
| 96 } | |
| 97 this._delayLine.setAttribute("x1", WebInspector.AnimationUI.Options.Anim ationMargin); | |
| 98 this._delayLine.setAttribute("x2", (this._delay() * this._timeline.pixel MsRatio() + WebInspector.AnimationUI.Options.AnimationMargin).toFixed(2)); | |
| 99 var leftMargin = (this._delay() + this._duration() * this._animation.sou rce().iterations()) * this._timeline.pixelMsRatio(); | |
| 100 this._endDelayLine.style.transform = "translateX(" + Math.min(leftMargin , this._timeline.width()).toFixed(2) + "px)"; | |
| 101 this._endDelayLine.setAttribute("x1", WebInspector.AnimationUI.Options.A nimationMargin); | |
| 102 this._endDelayLine.setAttribute("x2", (this._animation.source().endDelay () * this._timeline.pixelMsRatio() + WebInspector.AnimationUI.Options.AnimationM argin).toFixed(2)); | |
| 103 }, | |
| 104 | |
| 105 /** | |
| 106 * @param {number} iteration | |
| 107 * @param {!Element} parentElement | |
| 108 * @param {number} x | |
| 109 * @param {number} keyframeIndex | |
| 110 * @param {boolean} attachEvents | |
| 111 */ | |
| 112 _drawPoint: function(iteration, parentElement, x, keyframeIndex, attachEvent s) | |
| 113 { | |
| 114 if (this._cachedElements[iteration].keyframePoints[keyframeIndex]) { | |
| 115 this._cachedElements[iteration].keyframePoints[keyframeIndex].setAtt ribute("cx", x.toFixed(2)); | |
| 116 return; | |
| 117 } | |
| 118 | |
| 119 var circle = parentElement.createSVGChild("circle", keyframeIndex <= 0 ? "animation-endpoint" : "animation-keyframe-point"); | |
| 120 circle.setAttribute("cx", x.toFixed(2)); | |
| 121 circle.setAttribute("cy", WebInspector.AnimationUI.Options.AnimationHeig ht); | |
| 122 circle.style.stroke = this._color; | |
| 123 circle.setAttribute("r", WebInspector.AnimationUI.Options.AnimationMargi n / 2); | |
| 124 | |
| 125 if (keyframeIndex <= 0) | |
| 126 circle.style.fill = this._color; | |
| 127 | |
| 128 this._cachedElements[iteration].keyframePoints[keyframeIndex] = circle; | |
| 129 | |
| 130 if (!attachEvents) | |
| 131 return; | |
| 132 | |
| 133 if (keyframeIndex === 0) { | |
| 134 circle.addEventListener("mousedown", this._mouseDown.bind(this, WebI nspector.AnimationUI.MouseEvents.StartEndpointMove, keyframeIndex)); | |
| 135 } else if (keyframeIndex === -1) { | |
| 136 circle.addEventListener("mousedown", this._mouseDown.bind(this, WebI nspector.AnimationUI.MouseEvents.FinishEndpointMove, keyframeIndex)); | |
| 137 } else { | |
| 138 circle.addEventListener("mousedown", this._mouseDown.bind(this, WebI nspector.AnimationUI.MouseEvents.KeyframeMove, keyframeIndex)); | |
| 139 } | |
| 140 }, | |
| 141 | |
| 142 /** | |
| 143 * @param {number} iteration | |
| 144 * @param {number} keyframeIndex | |
| 145 * @param {!Element} parentElement | |
| 146 * @param {number} leftDistance | |
| 147 * @param {number} width | |
| 148 * @param {string} easing | |
| 149 */ | |
| 150 _renderKeyframe: function(iteration, keyframeIndex, parentElement, leftDista nce, width, easing) | |
| 151 { | |
| 152 /** | |
| 153 * @param {!Element} parentElement | |
| 154 * @param {number} x | |
| 155 * @param {string} strokeColor | |
| 156 */ | |
| 157 function createStepLine(parentElement, x, strokeColor) | |
| 158 { | |
| 159 var line = parentElement.createSVGChild("line"); | |
| 160 line.setAttribute("x1", x); | |
| 161 line.setAttribute("x2", x); | |
| 162 line.setAttribute("y1", WebInspector.AnimationUI.Options.AnimationMa rgin); | |
| 163 line.setAttribute("y2", WebInspector.AnimationUI.Options.AnimationHe ight); | |
| 164 line.style.stroke = strokeColor; | |
| 165 } | |
| 166 | |
| 167 var bezier = WebInspector.Geometry.CubicBezier.parse(easing); | |
| 168 var cache = this._cachedElements[iteration].keyframeRender; | |
| 169 if (!cache[keyframeIndex]) | |
| 170 cache[keyframeIndex] = bezier ? parentElement.createSVGChild("path", "animation-keyframe") : parentElement.createSVGChild("g", "animation-keyframe-s tep"); | |
| 171 var group = cache[keyframeIndex]; | |
| 172 group.style.transform = "translateX(" + leftDistance.toFixed(2) + "px)"; | |
| 173 | |
| 174 if (bezier) { | |
| 175 group.style.fill = this._color; | |
| 176 WebInspector.BezierUI.drawVelocityChart(bezier, group, width); | |
| 177 } else { | |
| 178 var stepFunction = WebInspector.AnimationTimeline.StepTimingFunction .parse(easing); | |
| 179 group.removeChildren(); | |
| 180 const offsetMap = {"start": 0, "middle": 0.5, "end": 1}; | |
| 181 const offsetWeight = offsetMap[stepFunction.stepAtPosition]; | |
| 182 for (var i = 0; i < stepFunction.steps; i++) | |
| 183 createStepLine(group, (i + offsetWeight) * width / stepFunction. steps, this._color); | |
| 184 } | |
| 185 }, | |
| 186 | |
| 187 redraw: function() | |
| 188 { | |
| 189 var durationWithDelay = this._delay() + this._duration() * this._animati on.source().iterations() + this._animation.source().endDelay(); | |
| 190 var leftMargin = ((this._animation.startTime() - this._timeline.startTim e()) * this._timeline.pixelMsRatio()); | |
| 191 var maxWidth = this._timeline.width() - WebInspector.AnimationUI.Options .AnimationMargin - leftMargin; | |
| 192 var svgWidth = Math.min(maxWidth, durationWithDelay * this._timeline.pix elMsRatio()); | |
| 193 | |
| 194 this._svg.classList.toggle("animation-ui-canceled", this._animation.play State() === "idle"); | |
| 195 this._svg.setAttribute("width", (svgWidth + 2 * WebInspector.AnimationUI .Options.AnimationMargin).toFixed(2)); | |
| 196 this._svg.style.transform = "translateX(" + leftMargin.toFixed(2) + "px )"; | |
| 197 this._activeIntervalGroup.style.transform = "translateX(" + (this._delay () * this._timeline.pixelMsRatio()).toFixed(2) + "px)"; | |
| 198 | |
| 199 this._nameElement.style.transform = "translateX(" + (leftMargin + this._ delay() * this._timeline.pixelMsRatio() + WebInspector.AnimationUI.Options.Anima tionMargin).toFixed(2) + "px)"; | |
| 200 this._nameElement.style.width = (this._duration() * this._timeline.pixel MsRatio().toFixed(2)) + "px"; | |
| 201 this._drawDelayLine(this._svg); | |
| 202 | |
| 203 if (this._animation.type() === "CSSTransition") { | |
| 204 this._renderTransition(); | |
| 205 return; | |
| 206 } | |
| 207 | |
| 208 this._renderIteration(this._activeIntervalGroup, 0); | |
| 209 if (!this._tailGroup) | |
| 210 this._tailGroup = this._activeIntervalGroup.createSVGChild("g", "ani mation-tail-iterations"); | |
| 211 var iterationWidth = this._duration() * this._timeline.pixelMsRatio(); | |
| 212 for (var iteration = 1; iteration < this._animation.source().iterations( ) && iterationWidth * (iteration - 1) < this._timeline.width(); iteration++) | |
| 213 this._renderIteration(this._tailGroup, iteration); | |
| 214 while (iteration < this._cachedElements.length) | |
| 215 this._cachedElements.pop().group.remove(); | |
| 216 }, | |
| 217 | |
| 218 | |
| 219 _renderTransition: function() | |
| 220 { | |
| 221 if (!this._cachedElements[0]) | |
| 222 this._cachedElements[0] = { animationLine: null, keyframePoints: {}, keyframeRender: {}, group: null }; | |
| 223 this._drawAnimationLine(0, this._activeIntervalGroup); | |
| 224 this._renderKeyframe(0, 0, this._activeIntervalGroup, WebInspector.Anima tionUI.Options.AnimationMargin, this._duration() * this._timeline.pixelMsRatio() , this._animation.source().easing()); | |
| 225 this._drawPoint(0, this._activeIntervalGroup, WebInspector.AnimationUI.O ptions.AnimationMargin, 0, true); | |
| 226 this._drawPoint(0, this._activeIntervalGroup, this._duration() * this._t imeline.pixelMsRatio() + WebInspector.AnimationUI.Options.AnimationMargin, -1, t rue); | |
| 227 }, | |
| 228 | |
| 229 /** | |
| 230 * @param {!Element} parentElement | |
| 231 * @param {number} iteration | |
| 232 */ | |
| 233 _renderIteration: function(parentElement, iteration) | |
| 234 { | |
| 235 if (!this._cachedElements[iteration]) | |
| 236 this._cachedElements[iteration] = { animationLine: null, keyframePoi nts: {}, keyframeRender: {}, group: parentElement.createSVGChild("g") }; | |
| 237 var group = this._cachedElements[iteration].group; | |
| 238 group.style.transform = "translateX(" + (iteration * this._duration() * this._timeline.pixelMsRatio()).toFixed(2) + "px)"; | |
| 239 this._drawAnimationLine(iteration, group); | |
| 240 console.assert(this._keyframes.length > 1); | |
| 241 for (var i = 0; i < this._keyframes.length - 1; i++) { | |
| 242 var leftDistance = this._offset(i) * this._duration() * this._timeli ne.pixelMsRatio() + WebInspector.AnimationUI.Options.AnimationMargin; | |
| 243 var width = this._duration() * (this._offset(i + 1) - this._offset(i )) * this._timeline.pixelMsRatio(); | |
| 244 this._renderKeyframe(iteration, i, group, leftDistance, width, this. _keyframes[i].easing()); | |
| 245 if (i || (!i && iteration === 0)) | |
| 246 this._drawPoint(iteration, group, leftDistance, i, iteration === 0); | |
| 247 } | |
| 248 this._drawPoint(iteration, group, this._duration() * this._timeline.pixe lMsRatio() + WebInspector.AnimationUI.Options.AnimationMargin, -1, iteration === 0); | |
| 249 }, | |
| 250 | |
| 251 /** | |
| 252 * @return {number} | |
| 253 */ | |
| 254 _delay: function() | |
| 255 { | |
| 256 var delay = this._animation.source().delay(); | |
| 257 if (this._mouseEventType === WebInspector.AnimationUI.MouseEvents.Animat ionDrag || this._mouseEventType === WebInspector.AnimationUI.MouseEvents.StartEn dpointMove) | |
| 258 delay += this._movementInMs; | |
| 259 // FIXME: add support for negative start delay | |
| 260 return Math.max(0, delay); | |
| 261 }, | |
| 262 | |
| 263 /** | |
| 264 * @return {number} | |
| 265 */ | |
| 266 _duration: function() | |
| 267 { | |
| 268 var duration = this._animation.source().duration(); | |
| 269 if (this._mouseEventType === WebInspector.AnimationUI.MouseEvents.Finish EndpointMove) | |
| 270 duration += this._movementInMs; | |
| 271 else if (this._mouseEventType === WebInspector.AnimationUI.MouseEvents.S tartEndpointMove) | |
| 272 duration -= Math.max(this._movementInMs, -this._animation.source().d elay()); // Cannot have negative delay | |
| 273 return Math.max(0, duration); | |
| 274 }, | |
| 275 | |
| 276 /** | |
| 277 * @param {number} i | |
| 278 * @return {number} offset | |
| 279 */ | |
| 280 _offset: function(i) | |
| 281 { | |
| 282 var offset = this._keyframes[i].offsetAsNumber(); | |
| 283 if (this._mouseEventType === WebInspector.AnimationUI.MouseEvents.Keyfra meMove && i === this._keyframeMoved) { | |
| 284 console.assert(i > 0 && i < this._keyframes.length - 1, "First and l ast keyframe cannot be moved"); | |
| 285 offset += this._movementInMs / this._animation.source().duration(); | |
| 286 offset = Math.max(offset, this._keyframes[i - 1].offsetAsNumber()); | |
| 287 offset = Math.min(offset, this._keyframes[i + 1].offsetAsNumber()); | |
| 288 } | |
| 289 return offset; | |
| 290 }, | |
| 291 | |
| 292 /** | |
| 293 * @param {!WebInspector.AnimationUI.MouseEvents} mouseEventType | |
| 294 * @param {?number} keyframeIndex | |
| 295 * @param {!Event} event | |
| 296 */ | |
| 297 _mouseDown: function(mouseEventType, keyframeIndex, event) | |
| 298 { | |
| 299 if (this._animation.playState() === "idle") | |
| 300 return; | |
| 301 this._mouseEventType = mouseEventType; | |
| 302 this._keyframeMoved = keyframeIndex; | |
| 303 this._downMouseX = event.clientX; | |
| 304 this._mouseMoveHandler = this._mouseMove.bind(this); | |
| 305 this._mouseUpHandler = this._mouseUp.bind(this); | |
| 306 this._parentElement.ownerDocument.addEventListener("mousemove", this._mo useMoveHandler); | |
| 307 this._parentElement.ownerDocument.addEventListener("mouseup", this._mous eUpHandler); | |
| 308 event.preventDefault(); | |
| 309 event.stopPropagation(); | |
| 310 | |
| 311 if (this._node) | |
| 312 WebInspector.Revealer.reveal(this._node); | |
| 313 }, | |
| 314 | |
| 315 /** | |
| 316 * @param {!Event} event | |
| 317 */ | |
| 318 _mouseMove: function (event) | |
| 319 { | |
| 320 this._movementInMs = (event.clientX - this._downMouseX) / this._timeline .pixelMsRatio(); | |
| 321 if (this._animation.startTime() + this._delay() + this._duration() - thi s._timeline.startTime() > this._timeline.duration() * 0.8) | |
| 322 this._timeline.setDuration(this._timeline.duration() * 1.2); | |
| 323 this.redraw(); | |
| 324 }, | |
| 325 | |
| 326 /** | |
| 327 * @param {!Event} event | |
| 328 */ | |
| 329 _mouseUp: function(event) | |
| 330 { | |
| 331 this._movementInMs = (event.clientX - this._downMouseX) / this._timeline .pixelMsRatio(); | |
| 332 | |
| 333 // Commit changes | |
| 334 if (this._mouseEventType === WebInspector.AnimationUI.MouseEvents.Keyfra meMove) { | |
| 335 this._keyframes[this._keyframeMoved].setOffset(this._offset(this._ke yframeMoved)); | |
| 336 } else { | |
| 337 var delay = this._delay(); | |
| 338 var duration = this._duration(); | |
| 339 this._setDelay(delay); | |
| 340 this._setDuration(duration); | |
| 341 if (this._animation.type() !== "CSSAnimation") { | |
| 342 var target = WebInspector.targetManager.mainTarget(); | |
| 343 if (target) | |
| 344 target.animationAgent().setTiming(this._animation.id(), dura tion, delay); | |
| 345 } | |
| 346 } | |
| 347 | |
| 348 this._movementInMs = 0; | |
| 349 this.redraw(); | |
| 350 | |
| 351 this._parentElement.ownerDocument.removeEventListener("mousemove", this. _mouseMoveHandler); | |
| 352 this._parentElement.ownerDocument.removeEventListener("mouseup", this._m ouseUpHandler); | |
| 353 delete this._mouseMoveHandler; | |
| 354 delete this._mouseUpHandler; | |
| 355 delete this._mouseEventType; | |
| 356 delete this._downMouseX; | |
| 357 delete this._keyframeMoved; | |
| 358 }, | |
| 359 | |
| 360 /** | |
| 361 * @param {number} value | |
| 362 */ | |
| 363 _setDelay: function(value) | |
| 364 { | |
| 365 if (!this._node || this._animation.source().delay() == this._delay()) | |
| 366 return; | |
| 367 | |
| 368 this._animation.source().setDelay(this._delay()); | |
| 369 var propertyName; | |
| 370 if (this._animation.type() == "CSSTransition") | |
| 371 propertyName = "transition-delay"; | |
| 372 else if (this._animation.type() == "CSSAnimation") | |
| 373 propertyName = "animation-delay"; | |
| 374 else | |
| 375 return; | |
| 376 this._setNodeStyle(propertyName, Math.round(value) + "ms"); | |
| 377 }, | |
| 378 | |
| 379 /** | |
| 380 * @param {number} value | |
| 381 */ | |
| 382 _setDuration: function(value) | |
| 383 { | |
| 384 if (!this._node || this._animation.source().duration() == value) | |
| 385 return; | |
| 386 | |
| 387 this._animation.source().setDuration(value); | |
| 388 var propertyName; | |
| 389 if (this._animation.type() == "CSSTransition") | |
| 390 propertyName = "transition-duration"; | |
| 391 else if (this._animation.type() == "CSSAnimation") | |
| 392 propertyName = "animation-duration"; | |
| 393 else | |
| 394 return; | |
| 395 this._setNodeStyle(propertyName, Math.round(value) + "ms"); | |
| 396 }, | |
| 397 | |
| 398 /** | |
| 399 * @param {string} name | |
| 400 * @param {string} value | |
| 401 */ | |
| 402 _setNodeStyle: function(name, value) | |
| 403 { | |
| 404 var style = this._node.getAttribute("style") || ""; | |
| 405 if (style) | |
| 406 style = style.replace(new RegExp("\\s*(-webkit-)?" + name + ":[^;]*; ?\\s*", "g"), ""); | |
| 407 var valueString = name + ": " + value; | |
| 408 this._node.setAttributeValue("style", style + " " + valueString + "; -we bkit-" + valueString + ";"); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 WebInspector.AnimationUI.Options = { | |
| 413 AnimationHeight: 32, | |
| 414 AnimationSVGHeight: 80, | |
| 415 AnimationMargin: 7, | |
| 416 EndpointsClickRegionSize: 10, | |
| 417 GridCanvasHeight: 40 | |
| 418 } | |
| 419 | |
| 420 WebInspector.AnimationUI.Colors = { | |
| 421 "Purple": WebInspector.Color.parse("#9C27B0"), | |
| 422 "Light Blue": WebInspector.Color.parse("#03A9F4"), | |
| 423 "Deep Orange": WebInspector.Color.parse("#FF5722"), | |
| 424 "Blue": WebInspector.Color.parse("#5677FC"), | |
| 425 "Lime": WebInspector.Color.parse("#CDDC39"), | |
| 426 "Blue Grey": WebInspector.Color.parse("#607D8B"), | |
| 427 "Pink": WebInspector.Color.parse("#E91E63"), | |
| 428 "Green": WebInspector.Color.parse("#0F9D58"), | |
| 429 "Brown": WebInspector.Color.parse("#795548"), | |
| 430 "Cyan": WebInspector.Color.parse("#00BCD4") | |
| 431 } | |
| 432 | |
| 433 | |
| 434 /** | |
| 435 * @param {!WebInspector.AnimationModel.Animation} animation | |
| 436 * @return {string} | |
| 437 */ | |
| 438 WebInspector.AnimationUI.Color = function(animation) | |
| 439 { | |
| 440 /** | |
| 441 * @param {string} string | |
| 442 * @return {number} | |
| 443 */ | |
| 444 function hash(string) | |
| 445 { | |
| 446 var hash = 0; | |
| 447 for (var i = 0; i < string.length; i++) | |
| 448 hash = (hash << 5) + hash + string.charCodeAt(i); | |
| 449 return Math.abs(hash); | |
| 450 } | |
| 451 | |
| 452 var names = Object.keys(WebInspector.AnimationUI.Colors); | |
| 453 var color = WebInspector.AnimationUI.Colors[names[hash(animation.name() || a nimation.id()) % names.length]]; | |
| 454 return color.asString(WebInspector.Color.Format.RGB); | |
| 455 } | |
| OLD | NEW |