diff --git a/example.html b/example.html index 2c3d7c3..65d48a4 100644 --- a/example.html +++ b/example.html @@ -26,7 +26,9 @@ color0: "#ffae23", // CSS string color1: [ 0, 128, 255 ], // RGB array color2: [ 0, 128, 255, 0.3 ], // RGB with alpha - color3: { h: 350, s: 0.9, v: 0.3 } // Hue, saturation, value + color3: { h: 350, s: 0.9, v: 0.3 }, // Hue, saturation, value + + imagePath1: 'https://images.unsplash.com/photo-1516222338250-863216ce01ea?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=467&q=50' }; var gui = new dat.gui.GUI(); @@ -58,6 +60,8 @@ var f3 = f2.addFolder('Nested Folder'); f3.add(obj, 'growthSpeed'); + var f4 = gui.addFolder('Image'); + f4.addImage(obj, 'imagePath1'); diff --git a/src/dat/controllers/ImageController.js b/src/dat/controllers/ImageController.js new file mode 100644 index 0000000..f4ce55f --- /dev/null +++ b/src/dat/controllers/ImageController.js @@ -0,0 +1,99 @@ +/** + * dat-gui JavaScript Controller Library + * https://github.com/dataarts/dat.gui + * + * Copyright 2011 Data Arts Team, Google Creative Lab + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +import Controller from './Controller'; +import dom from '../dom/dom'; +import common from '../utils/common'; + +/** + * @class Represents a image loaded throught its path, contains + * the preview to the image path. Another image can be loaded by + * clicking or dragging another image in the preview. + * + * @extends dat.controllers.Controller + * + * @param {Object} object The object to be manipulated + * @param {string} property The name of the property to be manipulated + */ +class ImageController extends Controller { + constructor(object, property) { + super(object, property); + + this.__fileReader = new FileReader(); + + const _this = this; + + this.__image = document.createElement('img'); + this.__imagePreview = document.createElement('img'); + this.__input = document.createElement('input'); + + common.extend(this.__imagePreview.style, { + display: 'block', + width: 'calc(100% + 5px)', + padding: '4px 0', + marginLeft: '-5px' + }); + + common.extend(this.__input.style, { + position: 'absolute', + top: '0', + left: '0', + width: '100%', + height: '100%', + opacity: '0', + cursor: 'pointer', + }); + + dom.bind(this.__image, 'load', imageLoaded); + dom.bind(this.__input, 'change', fileUploaded); + dom.bind(this.__fileReader, 'loadend', fileLoaded); + + function imageLoaded() { + _this.__imagePreview.src = _this.__image.src; + + if (_this.__onChange) { + _this.__onChange.call(_this, _this.__image); + } + } + + function fileUploaded() { + const file = _this.__input.files[0]; + if (!file) { + return; + } + _this.__fileReader.readAsDataURL(file); + } + + function fileLoaded() { + _this.__image.src = _this.__fileReader.result; + } + + this.__image.src = object[property]; + this.__imagePreview.src = object[property]; + this.__input.type = 'file'; + + this.domElement.appendChild(this.__imagePreview); + this.domElement.appendChild(this.__input); + } + + updateDisplay() { + if (this.isModified()) { + const newValue = this.getValue(); + this.__image.src = newValue; + this.initialValue = newValue; + } + return super.updateDisplay(); + } +} + +export default ImageController; diff --git a/src/dat/gui/GUI.js b/src/dat/gui/GUI.js index dbf1ae6..81dc4e5 100644 --- a/src/dat/gui/GUI.js +++ b/src/dat/gui/GUI.js @@ -20,6 +20,7 @@ import FunctionController from '../controllers/FunctionController'; import NumberControllerBox from '../controllers/NumberControllerBox'; import NumberControllerSlider from '../controllers/NumberControllerSlider'; import ColorController from '../controllers/ColorController'; +import ImageController from '../controllers/ImageController'; import requestAnimationFrame from '../utils/requestAnimationFrame'; import CenteredDiv from '../dom/CenteredDiv'; import dom from '../dom/dom'; @@ -556,6 +557,29 @@ common.extend( ); }, + /** + * Adds an image controller to the GUI. + * + * @param object + * @param property + * @returns {Controller} The controller that was added to the GUI. + * @instance + * + * @example + * var images = { path1: 'myImage.png'}; + * gui.addImage(images, 'path1'); + */ + addImage: function(object, property) { + return add( + this, + object, + property, + { + image: true + } + ); + }, + /** * Removes the given controller from the GUI. * @param {Controller} controller @@ -1140,6 +1164,8 @@ function add(gui, object, property, params) { if (params.color) { controller = new ColorController(object, property); + } else if (params.image) { + controller = new ImageController(object, property); } else { const factoryArgs = [object, property].concat(params.factoryArgs); controller = ControllerFactory.apply(gui, factoryArgs); @@ -1166,6 +1192,8 @@ function add(gui, object, property, params) { dom.addClass(li, GUI.CLASS_CONTROLLER_ROW); if (controller instanceof ColorController) { dom.addClass(li, 'color'); + } else if (controller instanceof ImageController) { + dom.addClass(li, 'image'); } else { dom.addClass(li, typeof controller.getValue()); } diff --git a/src/dat/gui/style.scss b/src/dat/gui/style.scss index 89705cd..84280ff 100644 --- a/src/dat/gui/style.scss +++ b/src/dat/gui/style.scss @@ -138,6 +138,12 @@ $input-color: lighten($background-color, 8.5%); border-left: 3px solid; } + &.image { + position: relative; + height: auto; + border-left: 3px solid; + } + &.function { border-left: 3px solid $function-color; }