<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[224303] trunk/Source/WebInspectorUI</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/224303">224303</a></dd>
<dt>Author</dt> <dd>ross.kirsling@sony.com</dd>
<dt>Date</dt> <dd>2017-11-01 15:47:14 -0700 (Wed, 01 Nov 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Improve UX of Layers tab visualization
https://bugs.webkit.org/show_bug.cgi?id=178966

Reviewed by Devin Rousso.

* UserInterface/Views/Layers3DContentView.js:
(WI.Layers3DContentView):
(WI.Layers3DContentView.prototype.initialLayout):
(WI.Layers3DContentView.prototype._canvasMouseDown):
(WI.Layers3DContentView.prototype._createLayerGroup): Renamed from _addLayerGroup.
(WI.Layers3DContentView.prototype._updateLayerGroupPosition): Merged into _updateLayers.
Set up zoom and pan.

(WI.Layers3DContentView.prototype._animate):
(WI.Layers3DContentView.prototype._restrictPan):
Restrict pan to bounding box on XY plane.

(WI.Layers3DContentView.prototype.layout):
(WI.Layers3DContentView.prototype._updateDocument):
(WI.Layers3DContentView.prototype._resetCamera):
On new document, throw out all old layers and center the camera on the new document layer.

(WI.Layers3DContentView.prototype.selectLayerById):
(WI.Layers3DContentView.prototype._centerOnSelection):
Recenter the camera when layer group selection is updated programmatically.

(WI.Layers3DContentView.prototype._updateLayers):
(WI.Layers3DContentView.prototype._createLayerMesh):
Fix visual artifact due to "depthWrite" flag.

* UserInterface/Views/LayerDetailsSidebarPanel.js:
(WI.LayerDetailsSidebarPanel.prototype.selectNodeByLayerId):
Suppress selection update event when the data grid selection is updated programmatically.

* UserInterface/Views/DataGridNode.js:
(WI.DataGridNode.prototype.revealAndSelect):
Allow forwarding of select()'s parameter.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsDataGridNodejs">trunk/Source/WebInspectorUI/UserInterface/Views/DataGridNode.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsLayerDetailsSidebarPaneljs">trunk/Source/WebInspectorUI/UserInterface/Views/LayerDetailsSidebarPanel.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsLayers3DContentViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/Layers3DContentView.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (224302 => 224303)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog    2017-11-01 22:35:56 UTC (rev 224302)
+++ trunk/Source/WebInspectorUI/ChangeLog       2017-11-01 22:47:14 UTC (rev 224303)
</span><span class="lines">@@ -1,3 +1,43 @@
</span><ins>+2017-11-01  Ross Kirsling  <ross.kirsling@sony.com>
+
+        Web Inspector: Improve UX of Layers tab visualization
+        https://bugs.webkit.org/show_bug.cgi?id=178966
+
+        Reviewed by Devin Rousso.
+
+        * UserInterface/Views/Layers3DContentView.js:
+        (WI.Layers3DContentView):
+        (WI.Layers3DContentView.prototype.initialLayout):
+        (WI.Layers3DContentView.prototype._canvasMouseDown):
+        (WI.Layers3DContentView.prototype._createLayerGroup): Renamed from _addLayerGroup.
+        (WI.Layers3DContentView.prototype._updateLayerGroupPosition): Merged into _updateLayers.
+        Set up zoom and pan.
+
+        (WI.Layers3DContentView.prototype._animate):
+        (WI.Layers3DContentView.prototype._restrictPan):
+        Restrict pan to bounding box on XY plane.
+
+        (WI.Layers3DContentView.prototype.layout):
+        (WI.Layers3DContentView.prototype._updateDocument):
+        (WI.Layers3DContentView.prototype._resetCamera):
+        On new document, throw out all old layers and center the camera on the new document layer.
+
+        (WI.Layers3DContentView.prototype.selectLayerById):
+        (WI.Layers3DContentView.prototype._centerOnSelection):
+        Recenter the camera when layer group selection is updated programmatically.
+
+        (WI.Layers3DContentView.prototype._updateLayers):
+        (WI.Layers3DContentView.prototype._createLayerMesh):
+        Fix visual artifact due to "depthWrite" flag.
+
+        * UserInterface/Views/LayerDetailsSidebarPanel.js:
+        (WI.LayerDetailsSidebarPanel.prototype.selectNodeByLayerId):
+        Suppress selection update event when the data grid selection is updated programmatically.
+
+        * UserInterface/Views/DataGridNode.js:
+        (WI.DataGridNode.prototype.revealAndSelect):
+        Allow forwarding of select()'s parameter.
+
</ins><span class="cx"> 2017-11-01  Joseph Pecoraro  <pecoraro@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Combine all storage icon files into a single file
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsDataGridNodejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/DataGridNode.js (224302 => 224303)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/DataGridNode.js  2017-11-01 22:35:56 UTC (rev 224302)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DataGridNode.js     2017-11-01 22:47:14 UTC (rev 224303)
</span><span class="lines">@@ -569,10 +569,10 @@
</span><span class="cx">             this.dataGrid.dispatchEventToListeners(WI.DataGrid.Event.SelectedNodeChanged, {oldSelectedNode});
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    revealAndSelect()
</del><ins>+    revealAndSelect(suppressSelectedEvent)
</ins><span class="cx">     {
</span><span class="cx">         this.reveal();
</span><del>-        this.select();
</del><ins>+        this.select(suppressSelectedEvent);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     deselect(suppressDeselectedEvent)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsLayerDetailsSidebarPaneljs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/LayerDetailsSidebarPanel.js (224302 => 224303)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/LayerDetailsSidebarPanel.js      2017-11-01 22:35:56 UTC (rev 224302)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/LayerDetailsSidebarPanel.js 2017-11-01 22:47:14 UTC (rev 224303)
</span><span class="lines">@@ -67,10 +67,11 @@
</span><span class="cx">         if (node === this._dataGrid.selectedNode)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><ins>+        const suppressEvent = true;
</ins><span class="cx">         if (node)
</span><del>-            node.revealAndSelect();
</del><ins>+            node.revealAndSelect(suppressEvent);
</ins><span class="cx">         else if (this._dataGrid.selectedNode)
</span><del>-            this._dataGrid.selectedNode.deselect();
</del><ins>+            this._dataGrid.selectedNode.deselect(suppressEvent);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Private
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsLayers3DContentViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/Layers3DContentView.js (224302 => 224303)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/Layers3DContentView.js   2017-11-01 22:35:56 UTC (rev 224302)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/Layers3DContentView.js      2017-11-01 22:47:14 UTC (rev 224303)
</span><span class="lines">@@ -42,9 +42,11 @@
</span><span class="cx">         this._camera = null;
</span><span class="cx">         this._controls = null;
</span><span class="cx">         this._scene = null;
</span><ins>+        this._boundingBox = null;
</ins><span class="cx">         this._raycaster = null;
</span><span class="cx">         this._mouse = null;
</span><span class="cx">         this._animationFrameRequestId = null;
</span><ins>+        this._documentNode = null;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Public
</span><span class="lines">@@ -86,6 +88,7 @@
</span><span class="cx">     {
</span><span class="cx">         let layerGroup = this._layerGroupsById.get(layerId);
</span><span class="cx">         this._updateLayerGroupSelection(layerGroup);
</span><ins>+        this._centerOnSelection();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Protected
</span><span class="lines">@@ -99,18 +102,19 @@
</span><span class="cx">         this._renderer.setSize(this.element.offsetWidth, this.element.offsetHeight);
</span><span class="cx"> 
</span><span class="cx">         this._camera = new THREE.PerspectiveCamera(45, this.element.offsetWidth / this.element.offsetHeight, 1, 100000);
</span><del>-        this._camera.position.set(0, 0, 4000);
-        this._camera.lookAt(new THREE.Vector3(0, 0, 0));
</del><span class="cx"> 
</span><span class="cx">         this._controls = new THREE.OrbitControls(this._camera, this._renderer.domElement);
</span><span class="cx">         this._controls.enableDamping = true;
</span><del>-        this._controls.enableZoom = false;
-        this._controls.enablePan = false;
</del><ins>+        this._controls.enableKeys = false;
+        this._controls.zoomSpeed = 0.5;
+        this._controls.minDistance = 1000;
+        this._controls.rotateSpeed = 0.5;
</ins><span class="cx">         this._controls.minAzimuthAngle = -Math.PI / 2;
</span><span class="cx">         this._controls.maxAzimuthAngle = Math.PI / 2;
</span><ins>+        this._renderer.domElement.addEventListener("contextmenu", (event) => { event.stopPropagation(); });
</ins><span class="cx"> 
</span><span class="cx">         this._scene = new THREE.Scene;
</span><del>-        this._scene.position.set(-this.element.offsetWidth / 2, this.element.offsetHeight / 2, 0);
</del><ins>+        this._boundingBox = new THREE.Box3;
</ins><span class="cx"> 
</span><span class="cx">         this._raycaster = new THREE.Raycaster;
</span><span class="cx">         this._mouse = new THREE.Vector2;
</span><span class="lines">@@ -127,9 +131,12 @@
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         WI.domTreeManager.requestDocument((node) => {
</span><ins>+            let documentWasUpdated = this._updateDocument(node);
+
</ins><span class="cx">             WI.layerTreeManager.layersForNode(node, (layers) => {
</span><span class="cx">                 this._updateLayers(layers);
</span><del>-                this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
</del><ins>+                if (documentWasUpdated)
+                    this._resetCamera();
</ins><span class="cx">             });
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="lines">@@ -160,6 +167,7 @@
</span><span class="cx">     _animate()
</span><span class="cx">     {
</span><span class="cx">         this._controls.update();
</span><ins>+        this._restrictPan();
</ins><span class="cx">         this._renderer.render(this._scene, this._camera);
</span><span class="cx">         this._animationFrameRequestId = requestAnimationFrame(() => { this._animate(); });
</span><span class="cx">     }
</span><span class="lines">@@ -170,11 +178,25 @@
</span><span class="cx">         this._animationFrameRequestId = null;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    _updateDocument(documentNode)
+    {
+        if (documentNode === this._documentNode)
+            return false;
+
+        this._scene.children.length = 0;
+        this._layerGroupsById.clear();
+        this._layers.length = 0;
+
+        this._documentNode = documentNode;
+
+        return true;
+    }
+
</ins><span class="cx">     _updateLayers(newLayers)
</span><span class="cx">     {
</span><span class="cx">         // FIXME: This should be made into the basic usage of the manager, if not the agent itself.
</span><span class="cx">         //        At that point, we can remove this duplication from the visualization and sidebar.
</span><del>-        let {removals, additions, preserved} = WI.layerTreeManager.layerTreeMutations(this._layers, newLayers);
</del><ins>+        let {removals, additions} = WI.layerTreeManager.layerTreeMutations(this._layers, newLayers);
</ins><span class="cx"> 
</span><span class="cx">         for (let layer of removals) {
</span><span class="cx">             let layerGroup = this._layerGroupsById.get(layer.layerId);
</span><span class="lines">@@ -182,43 +204,45 @@
</span><span class="cx">             this._layerGroupsById.delete(layer.layerId);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (this._selectedLayerGroup && !this._layerGroupsById.get(this._selectedLayerGroup.userData.layerId))
</del><ins>+        if (this._selectedLayerGroup && !this._layerGroupsById.get(this._selectedLayerGroup.userData.layer.layerId))
</ins><span class="cx">             this.selectedLayerGroup = null;
</span><span class="cx"> 
</span><del>-        additions.forEach(this._addLayerGroup, this);
-        preserved.forEach(this._updateLayerGroupPosition, this);
</del><ins>+        for (let layer of additions) {
+            let layerGroup = this._createLayerGroup(layer);
+            this._layerGroupsById.set(layer.layerId, layerGroup);
+            this._scene.add(layerGroup);
+        }
</ins><span class="cx"> 
</span><ins>+        // FIXME: Update the backend to provide a literal "layer tree" so we can decide z-indices less naively.
+        const zInterval = 25;
+        newLayers.forEach((layer, index) => {
+            let layerGroup = this._layerGroupsById.get(layer.layerId);
+            layerGroup.position.set(layer.bounds.x, -layer.bounds.y, index * zInterval);
+        });
+
+        this._boundingBox.setFromObject(this._scene);
+        this._controls.maxDistance = this._boundingBox.max.z + WI.Layers3DContentView._zPadding;
+
</ins><span class="cx">         this._layers = newLayers;
</span><ins>+        this.dispatchEventToListeners(WI.ContentView.Event.SelectionPathComponentsDidChange);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _addLayerGroup(layer, index)
-    {
</del><ins>+    _createLayerGroup(layer) {
</ins><span class="cx">         let layerGroup = new THREE.Group;
</span><del>-        layerGroup.userData.layerId = layer.layerId;
-        layerGroup.add(this._createLayerMesh(layer.bounds));
-        layerGroup.add(this._createLayerMesh(layer.compositedBounds, true));
-
-        this._layerGroupsById.set(layer.layerId, layerGroup);
-        this._updateLayerGroupPosition(layer, index);
-
-        this._scene.add(layerGroup);
</del><ins>+        layerGroup.userData.layer = layer;
+        layerGroup.add(this._createLayerMesh(layer.bounds), this._createLayerMesh(layer.compositedBounds, true));
+        return layerGroup;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _updateLayerGroupPosition(layer, index) {
-        let layerGroup = this._layerGroupsById.get(layer.layerId);
-        console.assert(layerGroup);
-
-        const zInterval = 25;
-        layerGroup.position.set(layer.bounds.x, -layer.bounds.y, index * zInterval);
-    }
-
</del><span class="cx">     _createLayerMesh({width, height}, isOutline = false)
</span><span class="cx">     {
</span><span class="cx">         let geometry = new THREE.Geometry;
</span><del>-        geometry.vertices.push(new THREE.Vector3(0,     0,       0));
-        geometry.vertices.push(new THREE.Vector3(width, 0,       0));
-        geometry.vertices.push(new THREE.Vector3(width, -height, 0));
-        geometry.vertices.push(new THREE.Vector3(0,     -height, 0));
</del><ins>+        geometry.vertices.push(
+            new THREE.Vector3(0,     0,       0),
+            new THREE.Vector3(0,     -height, 0),
+            new THREE.Vector3(width, -height, 0),
+            new THREE.Vector3(width, 0,       0),
+        );
</ins><span class="cx"> 
</span><span class="cx">         if (isOutline) {
</span><span class="cx">             let material = new THREE.LineBasicMaterial({color: WI.Layers3DContentView._layerColor.stroke});
</span><span class="lines">@@ -225,8 +249,7 @@
</span><span class="cx">             return new THREE.LineLoop(geometry, material);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        geometry.faces.push(new THREE.Face3(0, 1, 3));
-        geometry.faces.push(new THREE.Face3(1, 2, 3));
</del><ins>+        geometry.faces.push(new THREE.Face3(0, 1, 3), new THREE.Face3(1, 2, 3));
</ins><span class="cx"> 
</span><span class="cx">         let material = new THREE.MeshBasicMaterial({
</span><span class="cx">             color: WI.Layers3DContentView._layerColor.fill,
</span><span class="lines">@@ -233,6 +256,7 @@
</span><span class="cx">             transparent: true,
</span><span class="cx">             opacity: 0.4,
</span><span class="cx">             side: THREE.DoubleSide,
</span><ins>+            depthWrite: false,
</ins><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         return new THREE.Mesh(geometry, material);
</span><span class="lines">@@ -256,7 +280,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._updateLayerGroupSelection(selection);
</span><span class="cx"> 
</span><del>-        let layerId = selection ? selection.userData.layerId : null;
</del><ins>+        let layerId = selection ? selection.userData.layer.layerId : null;
</ins><span class="cx">         this.dispatchEventToListeners(WI.Layers3DContentView.Event.SelectedLayerChanged, {layerId});
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -276,8 +300,34 @@
</span><span class="cx">         if (this._selectedLayerGroup)
</span><span class="cx">             setColor(WI.Layers3DContentView._selectedLayerColor);
</span><span class="cx">     }
</span><ins>+
+    _centerOnSelection()
+    {
+        if (!this._selectedLayerGroup)
+            return;
+
+        let {x, y, width, height} = this._selectedLayerGroup.userData.layer.bounds;
+        this._controls.target.set(x + (width / 2), -y - (height / 2), 0);
+        this._camera.position.set(x + (width / 2), -y - (height / 2), this._selectedLayerGroup.position.z + WI.Layers3DContentView._zPadding / 2);
+    }
+
+    _resetCamera()
+    {
+        let {x, y, width, height} = this._layers[0].bounds;
+        this._controls.target.set(x + (width / 2), -y - (height / 2), 0);
+        this._camera.position.set(x + (width / 2), -y - (height / 2), this._controls.maxDistance - WI.Layers3DContentView._zPadding / 2);
+    }
+
+    _restrictPan()
+    {
+        let delta = this._boundingBox.clampPoint(this._controls.target).setZ(0).sub(this._controls.target);
+        this._controls.target.add(delta);
+        this._camera.position.add(delta);
+    }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><ins>+WI.Layers3DContentView._zPadding = 3000;
+
</ins><span class="cx"> WI.Layers3DContentView._layerColor = {
</span><span class="cx">     fill: "hsl(76, 49%, 75%)",
</span><span class="cx">     stroke: "hsl(79, 45%, 50%)"
</span></span></pre>
</div>
</div>

</body>
</html>