This exercise is a good demonstration of an important principle: you don't have to have any idea what you are doing to get in there and change things up.
When I was making my Manifesto page, I kept being annoyed by a mysterious, ugly control panel that clung to the top-right of my screen and wouldn't be moved.
Finally, I noticed that it had a "Close" button, so I was able to make it retreat, but then it lurked like a cockroach at the corner of my page, and reappeared full-size every time I refreshed.
Gradually, I came to understand what that little box was doing, and I saw the light. How awesome is that? A little panel that lets you change the original programmer's variables on the fly!
For example, here is my Columbine flag with low gravity, then high gravity.
Fun! If you haven't tried it yet, you should go to my Manifesto page and remove the pins that are holding up my flag. Isn't that a cool effect?
Until yesterday, I thought dat-GUI was part of Pixi.js. (GUI stands for 'graphical user interface,' by the way.). It wouldn't be worth "fixing up" if I was never going to use it again. But now that I understand that it's something you can use with any javascript program, it seems like an incredibly useful tool to have around, if only to impress readers with my programmer-like skills.
See, I can't take any credit for programming my "dangling cloth photo flag" myself (check out this guy and this guy), but it would still be impressive if I could say, "Hey, readers, while you're here, check out my mouseInfluence slider!"
But egads, it really is so ugly. It totally doesn't match my purply-bluey color scheme. And it doesn't have any place to put instructions for the user. It's really just a basic HTML input form, though, isn't it? Buttons and checkboxes and drop-downs, those can't be too hard to stylize, right?
The tricky part is that the interface is created on the fly by a javascript program that loads when the page loads. So you can't just look at the raw HTML and target the various controls with CSS. If you right-click and look at the source code for the page, you won't see the dat-GUI at all. So how can we target it?
Luckily, I've been mucking around a bit, so I have a head-start. I'm going to write this blog post as I am actually doing it, so you can follow along and modify it to suit your own purposes.
What is dat-GUI, briefly?
"dat.GUI is a GUI widget for your demos." The best place to see it in action is on this demo page for threejs. And you can check out awesome examples of 3-D rendering while you're at it.
It is a "lightweight controller library for JavaScript," made by Google, and kept here on GitHub
Here is a nice tutorial for using it, and here is where you can find the latest CDN version.
Here is a sweet little example which shows how you would create a rectangle and then vary all its options with a dat-GUI: https://codepen.io/webhacck/pen/mVQJVj
Here is an intense example showing a huge number of physics properties in one giant model: http://brm.io/matter-js/demo/#mixed
It consists of a single javascript file that you at the bottom of your HTML file in the usual way, such as:
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.1/dat.gui.min.js"></script>
But if you are going to edit some of the variables I mention below, you will probably want to use the un-minified version, which you can copy from here:
https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.1/dat.gui.js
I am using the most recent version 0.7.1 even though my project originally used 0.6.1 because I haven't noticed any changes in terms of how my flag controller works.
In addition to the actual dat.gui.js file, you will need the code that actually creates the GUI in the first place. I am working with the code that was written on the Codepen that I am borrowing from. I am assuming you are here because you already have a dat-GUI that you want to pretty up. If not, go borrow some code from the demo place that I mentioned.
The brute force method of CSS extraction
Before it occurred to me to look into the actual javascript file, I was planning to simply right-click on the widget and use the "inspector" tools available in Chrome and Firefox to figure out the CSS that we needed. Often, this very effective. Here, for example, you can see that the class name we need to target is "property-name".
What I like to do is create a mini stylesheet that targets each class or ID I find in the most extreme way possible.
span.property-name{
background-color: midnightblue;
color: white;
text-align: center;
font-family: serif;
font-size: 1.1em;
border-radius: 15px;
border: 2px purple ridge;
display: inline-block;
height: 30px;
line-height: 2em;
}
It's a good exercise for your brain to spew out random CSS properties and colors as quickly as you can. The goal is to make every item completely different from the others, so you can see exactly what each class or ID is targeting. Soon, you will have converted that boring, black GUI utility into an exciting, colorful monstrosity like this:
It's especially important to place brightly colored borders around things, which can reveal surprises, like when certain borders extend beyond the edges of their container.
Once you have figured out what's what, it's a simple matter to go back and tone down and up-class the mini CSS sheet you have created.
But sometimes you will get frustrated, because things just don't respond to your commands. The height of the rows, for example, seem to be impervious to the charms of my CSS.
Digging into the javascript
I won't bore you with the details of my explorations because I want to finish this project before I fall asleep tonight. I will just tell you a few things I have learned so far.
To free the GUI from its prison on the top right corner, do this
The first task is to rip that sticky beast off the top right side of your screen. And the way to do that, I have discovered, is to add this line to your code:
{ autoPlace: false }
More specifically, you want to add that to the place in your code where you actually create the new GUI, and you want to tell it where to put it instead. So you will see something like this:
let gui = new dat.GUI();
and you want to change it to something like this:
let gui = new dat.GUI({ autoPlace: false });
var GUIContainer = document.getElementById('my-gui-container');
GUIContainer.appendChild(gui.domElement);
Then, in your CSS you would want to position it where you want it to land. To do that, you need to use "absolute" positioning.<a href="javascript:void(0)" class="popover-dismiss" data-toggle="popover" data-trigger="hover" title="" data-content="If position:absolute doesn't work, remember that your container should be relative, not static.">
#my-gui-container {
position: absolute;
left: 600px; /* position inside relatively positioned parent */
top: 150px;
z-index: 0; /* adjust as needed */
}
Changes you can make to the javascript itself... if you do, you must keep track of it forever
Adust the default width variable
In the JS, you can change the default width for the entire controller by changing this variable:
GUI.DEFAULT_WIDTH = 245;
Change the wording on the Open and Close buttons
While you are there, you can change the text
//GUI.TEXT_CLOSED = 'Close Controls';
GUI.TEXT_CLOSED = 'Hide this control box';
//GUI.TEXT_OPEN = 'Open Controls';
GUI.TEXT_OPEN = 'Goof around with my Flag';
To get rid of the ugly skinny left borders
Comment out or change the colors on these:
/*
* GETTING RID OF THE UGLY LEFT BORDERS
.dg .cr.boolean {
border-left: 3px solid #806787
}
.dg .cr.color {
border-left: 3px solid
}
.dg .cr.function {
border-left: 3px solid #e61d5f
}
.dg .cr.number {
border-left: 3px solid #2FA1D6
}
*/
Extract the CSS from the JS file
Luckily, we don't have to "figure out" the CSS that we need, because there is a CSS style sheet buried in the javascript file. Just search for "var styleSheet"
Yep, the entire, 400+ line stylesheet is just a single variable in javascript.
Now let's look at it!
Raw stylesheet extracted from 0.7.1 of dat.GUI
.dg ul {
list-style: none;
margin: 0;
padding: 0;
width: 100%;
clear: both
}
.dg.ac {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 0;
z-index: 0
}
.dg:not(.ac) .main {
overflow: hidden
}
.dg.main {
-webkit-transition: opacity .1s linear;
-o-transition: opacity .1s linear;
-moz-transition: opacity .1s linear;
transition: opacity .1s linear
}
.dg.main.taller-than-window {
overflow-y: auto
}
.dg.main.taller-than-window .close-button {
opacity: 1;
margin-top: -1px;
border-top: 1px solid #2c2c2c
}
.dg.main ul.closed .close-button {
opacity: 1 !important
}
.dg.main:hover .close-button,
.dg.main .close-button.drag {
opacity: 1
}
.dg.main .close-button {
-webkit-transition: opacity .1s linear;
-o-transition: opacity .1s linear;
-moz-transition: opacity .1s linear;
transition: opacity .1s linear;
border: 0;
line-height: 19px;
height: 20px;
cursor: pointer;
text-align: center;
background-color: #000
}
.dg.main .close-button.close-top {
position: relative
}
.dg.main .close-button.close-bottom {
position: absolute
}
.dg.main .close-button:hover {
background-color: #111
}
.dg.a {
float: right;
margin-right: 15px;
overflow-y: visible
}
.dg.a.has-save>ul.close-top {
margin-top: 0
}
.dg.a.has-save>ul.close-bottom {
margin-top: 27px
}
.dg.a.has-save>ul.closed {
margin-top: 0
}
.dg.a .save-row {
top: 0;
z-index: 1002
}
.dg.a .save-row.close-top {
position: relative
}
.dg.a .save-row.close-bottom {
position: fixed
}
.dg li {
-webkit-transition: height .1s ease-out;
-o-transition: height .1s ease-out;
-moz-transition: height .1s ease-out;
transition: height .1s ease-out;
-webkit-transition: overflow .1s linear;
-o-transition: overflow .1s linear;
-moz-transition: overflow .1s linear;
transition: overflow .1s linear
}
.dg li:not(.folder) {
cursor: auto;
height: 27px;
line-height: 27px;
padding: 0 4px 0 5px
}
.dg li.folder {
padding: 0;
border-left: 4px solid transparent
}
.dg li.title {
cursor: pointer;
margin-left: -4px
}
.dg .closed li:not(.title),
.dg .closed ul li,
.dg .closed ul li>* {
height: 0;
overflow: hidden;
border: 0
}
.dg .cr {
clear: both;
padding-left: 3px;
height: 27px;
overflow: hidden
}
.dg .property-name {
cursor: default;
float: left;
clear: left;
width: 40%;
overflow: hidden;
text-overflow: ellipsis
}
.dg .c {
float: left;
width: 60%;
position: relative
}
.dg .c input[type=text] {
border: 0;
margin-top: 4px;
padding: 3px;
width: 100%;
float: right
}
.dg .has-slider input[type=text] {
width: 30%;
margin-left: 0
}
.dg .slider {
float: left;
width: 66%;
margin-left: -5px;
margin-right: 0;
height: 19px;
margin-top: 4px
}
.dg .slider-fg {
height: 100%
}
.dg .c input[type=checkbox] {
margin-top: 7px
}
.dg .c select {
margin-top: 5px
}
.dg .cr.function,
.dg .cr.function .property-name,
.dg .cr.function *,
.dg .cr.boolean,
.dg .cr.boolean * {
cursor: pointer
}
.dg .cr.color {
overflow: visible
}
.dg .selector {
display: none;
position: absolute;
margin-left: -9px;
margin-top: 23px;
z-index: 10
}
.dg .c:hover .selector,
.dg .selector.drag {
display: block
}
.dg li.save-row {
padding: 0
}
.dg li.save-row .button {
display: inline-block;
padding: 0px 6px
}
.dg.dialogue {
background-color: #222;
width: 460px;
padding: 15px;
font-size: 13px;
line-height: 15px
}
#dg-new-constructor {
padding: 10px;
color: #222;
font-family: Monaco, monospace;
font-size: 10px;
border: 0;
resize: none;
box-shadow: inset 1px 1px 1px #888;
word-wrap: break-word;
margin: 12px 0;
display: block;
width: 440px;
overflow-y: scroll;
height: 100px;
position: relative
}
#dg-local-explain {
display: none;
font-size: 11px;
line-height: 17px;
border-radius: 3px;
background-color: #333;
padding: 8px;
margin-top: 10px
}
#dg-local-explain code {
font-size: 10px
}
#dat-gui-save-locally {
display: none
}
.dg {
color: #eee;
font: 11px 'Lucida Grande', sans-serif;
text-shadow: 0 -1px 0 #111
}
.dg.main::-webkit-scrollbar {
width: 5px;
background: #1a1a1a
}
.dg.main::-webkit-scrollbar-corner {
height: 0;
display: none
}
.dg.main::-webkit-scrollbar-thumb {
border-radius: 5px;
background: #676767
}
.dg li:not(.folder) {
background: #1a1a1a;
border-bottom: 1px solid #2c2c2c
}
.dg li.save-row {
line-height: 25px;
background: #dad5cb;
border: 0
}
.dg li.save-row select {
margin-left: 5px;
width: 108px
}
.dg li.save-row .button {
margin-left: 5px;
margin-top: 1px;
border-radius: 2px;
font-size: 9px;
line-height: 7px;
padding: 4px 4px 5px 4px;
background: #c5bdad;
color: #fff;
text-shadow: 0 1px 0 #b0a58f;
box-shadow: 0 -1px 0 #b0a58f;
cursor: pointer
}
.dg li.save-row .button.gears {
background: #c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;
height: 7px;
width: 8px
}
.dg li.save-row .button:hover {
background-color: #bab19e;
box-shadow: 0 -1px 0 #b0a58f
}
.dg li.folder {
border-bottom: 0
}
.dg li.title {
padding-left: 16px;
background: #000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;
cursor: pointer;
border-bottom: 1px solid rgba(255, 255, 255, 0.2)
}
.dg .closed li.title {
background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)
}
.dg .cr.boolean {
border-left: 3px solid #806787
}
.dg .cr.color {
border-left: 3px solid
}
.dg .cr.function {
border-left: 3px solid #e61d5f
}
.dg .cr.number {
border-left: 3px solid #2FA1D6
}
.dg .cr.number input[type=text] {
color: #2FA1D6
}
.dg .cr.string {
border-left: 3px solid #1ed36f
}
.dg .cr.string input[type=text] {
color: #1ed36f
}
.dg .cr.function:hover,
.dg .cr.boolean:hover {
background: #111
}
.dg .c input[type=text] {
background: #303030;
outline: none
}
.dg .c input[type=text]:hover {
background: #3c3c3c
}
.dg .c input[type=text]:focus {
background: #494949;
color: #fff
}
.dg .c .slider {
background: #303030;
cursor: ew-resize
}
.dg .c .slider-fg {
background: #2FA1D6;
max-width: 100%
}
.dg .c .slider:hover {
background: #3c3c3c
}
.dg .c .slider:hover .slider-fg {
background: #44abda
}