diff options
7 files changed, 390 insertions, 21 deletions
diff --git a/public/assets/javascripts/rectangles/engine/scenery/resize.js b/public/assets/javascripts/rectangles/engine/scenery/resize.js index 73fd82a..a5e255a 100644 --- a/public/assets/javascripts/rectangles/engine/scenery/resize.js +++ b/public/assets/javascripts/rectangles/engine/scenery/resize.js @@ -49,6 +49,7 @@ Scenery.resize = new function(){ // rotate the dots as appropriate base.rotate_dots = function(){ + console.trace() rotationY = obj.wall.rotationY dots.forEach(function(dot){ dot.rotationY = rotationY diff --git a/public/assets/javascripts/rectangles/engine/sculpture/move.js b/public/assets/javascripts/rectangles/engine/sculpture/move.js new file mode 100644 index 0000000..b5a4b40 --- /dev/null +++ b/public/assets/javascripts/rectangles/engine/sculpture/move.js @@ -0,0 +1,158 @@ + +Sculpture.move = function(base){ + + var x, y, z, position, dimension, bounds + var dragging = false, moved = false + var oldState + + this.bind = function(){ + Sculpture.mouse.bind_el(base.mx.el) + Sculpture.mouse.on("down", down) + Sculpture.mouse.on("enter", switch_wall) + Sculpture.mouse.on("drag", drag) + Sculpture.mouse.on("up", up) + } + + this.unbind = function(){ + base.focused = false + Sculpture.mouse.unbind_el(base.mx.el) + Sculpture.mouse.off("down", down) + Sculpture.mouse.off("enter", switch_wall) + Sculpture.mouse.off("drag", drag) + Sculpture.mouse.off("up", up) + } + + function down (e, cursor){ + if (e.target != base.mx.el && (e.target != base.mx.overlay)) return; + if (editor.permissions.destroy) { + base.remove() + return + } + + // load the modal + app.controller.pick(base) + + if (! base.focused) { + e.clickAccepted = false + base.focused = true + return + } + if (! (editor.permissions.move || editor.permissions.resize) ) { + e.clickAccepted = false + return + } + dragging = true + moved = false + x = base.mx.x + y = base.mx.y + z = base.mx.z + + bounds = base.bounds + dimension = base.dimensions + position = base.wall.mxToPosition( base.mx, dimension ) + + oldState = base.serialize() + document.body.classList.add("dragging") + } + + function drag (e, cursor){ + if (! dragging) return + + moved = true + + var flipX = base.wall.side & (FRONT | RIGHT) + + var delta = cursor.delta() + delta.mul( cursor_amp ) // TODO: this should be proportional to your distance from the wall + if (flipX) { delta.a *= -1 } + delta.b *= -1 + + var new_bounds = base.wall.surface.translate( bounds, dimension, position, delta ) + if (new_bounds) bounds = new_bounds + if (flipX) { delta.a *= -1 } + + base.mx.y = position.b + delta.b + dimension.b / 2 + switch (base.wall.side) { + case FRONT: + case BACK: + base.mx.x = position.a + delta.a * cos(base.wall.rotationY) + dimension.a / 2 + break + case LEFT: + case RIGHT: + base.mx.z = position.a + delta.a * sin(base.wall.rotationY) + dimension.a / 2 + break + } + + if (editor.permissions.resize) { + Sculpture.resize.move_dots() + } + } + + function up (e, cursor){ + if (! dragging || ! oldState) return + + if (moved) { + UndoStack.push({ + type: 'update-sculpture', + undo: oldState, + redo: base.serialize(), + }) + + // TODO: watch individual sculpture object here + Minotaur.watch( app.router.editorView.settings ) + } + + dragging = moved = false + oldState = null + document.body.classList.remove("dragging") + } + + function switch_wall (e, target, cursor){ + if (! dragging) return + if (target.wall.id == base.wall.id) return + + var old_wall_side = base.wall.side + var wall_group = old_wall_side | target.wall.side + var new_bounds = target.wall.surface.bounds_at_index_with_dimensions(target.index || 0, dimension) + + if (! new_bounds) return + + base.wall = target.wall + base.bounds = bounds = new_bounds + + position.a = bounds.x.midpoint() - dimension.a / 2 + + if (old_wall_side !== target.wall.side && wall_group !== FRONT_BACK && wall_group !== LEFT_RIGHT) { + switch (old_wall_side) { + case FRONT: + position.a = bounds.x.a + dimension.a / 2 + break + case BACK: + position.a = bounds.x.b - dimension.a / 2 + break + case LEFT: + position.a = bounds.x.a + dimension.a / 2 + break + case RIGHT: + position.a = bounds.x.b - dimension.a / 2 + break + } + } + + var mx_delta = base.wall.positionToMx( position, dimension ) + base.mx.move(mx_delta) + + if (editor.permissions.resize) { + Sculpture.resize.rotate_dots() + Sculpture.resize.move_dots() + } + + cursor.x.a = cursor.x.b + //var delta = cursor.delta() + drag(e, cursor) + + } + + return this + +}
\ No newline at end of file diff --git a/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js b/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js index fa6b0b1..6c93b41 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/types/_object.js @@ -8,8 +8,14 @@ Sculpture.types.base = Fiber.extend(function(base){ this.media = opt.media this.naturalDimensions = new vec2(this.media.width, this.media.height) + this.move = new Sculpture.move (this) + this.billboard = true + this.backface = true + this.set_scale( opt.scale || this.media.scale || 1.0 ) this.position = new vec2(0,0) + + this.isSculpture = true }, set_scale: function(scale){ @@ -30,11 +36,11 @@ Sculpture.types.base = Fiber.extend(function(base){ }, bind: function(){ - // this.move.bind() + this.move.bind() }, unbind: function(){ - // this.move.unbind() + this.move.unbind() }, remove: function(){ @@ -81,9 +87,21 @@ Sculpture.types.base = Fiber.extend(function(base){ position: app.position(this.mx), scale: this.scale, media: this.media, + billboard: this.billboard, + backface: this.backface, } return data }, + + deserialize: function(data){ + this.mx.move(data.position) + this.mx.ops.width = data.dimensions.a + this.mx.ops.height = data.dimensions.b + this.billboard = data.billboard + this.backface = data.backface + if (! this.backface) this.mx.el.classList.remove("backface-visible") + this.dimensions.deserialize(data.dimensions) + }, } return exports diff --git a/public/assets/javascripts/rectangles/engine/sculpture/types/image.js b/public/assets/javascripts/rectangles/engine/sculpture/types/image.js index 9e8de58..3e5ab08 100644 --- a/public/assets/javascripts/rectangles/engine/sculpture/types/image.js +++ b/public/assets/javascripts/rectangles/engine/sculpture/types/image.js @@ -27,29 +27,11 @@ Sculpture.types.image = Sculpture.types.base.extend(function(base){ if (opt.position) { opt.position.y = opt.position.y || this.scale * this.media.height/2 + 3 opt.position.rotationY = opt.position.rotationY || scene.camera.rotationY - this.billboard = true - this.backface = true } scene.add( this.mx ) }, - serialize: function(){ - var data = base.serialize.call(this) - data.billboard = this.billboard - data.backface = this.backface - return data - }, - - deserialize: function(data){ - this.mx.move(data.position) - this.mx.ops.width = data.dimensions.a - this.mx.ops.height = data.dimensions.b - this.billboard = data.billboard - this.backface = data.backface - if (! this.backface) this.mx.el.classList.remove("backface-visible") - this.dimensions.deserialize(data.dimensions) - }, } return exports diff --git a/public/assets/javascripts/ui/editor/EditorView.js b/public/assets/javascripts/ui/editor/EditorView.js index 50d3650..e5e2ca0 100644 --- a/public/assets/javascripts/ui/editor/EditorView.js +++ b/public/assets/javascripts/ui/editor/EditorView.js @@ -17,6 +17,7 @@ var EditorView = View.extend({ this.mediaUpload = new MediaUpload ({ parent: this }) this.mediaTumblr = new MediaTumblr ({ parent: this }) this.mediaEditor = new MediaEditor ({ parent: this }) + this.sculptureEditor = new SculptureEditor ({ parent: this }) this.wallpaperPicker = new WallpaperPicker ({ parent: this }) this.colorControl = new ColorControl ({ parent: this }) this.textEditor = new TextEditor ({ parent: this }) @@ -56,12 +57,19 @@ var EditorView = View.extend({ }, pick: function(scenery){ - if (scenery.type == "text") { + if (scenery.isSculpture) { this.mediaEditor.hide() + this.textEditor.hide() + this.sculptureEditor.pick(scenery) + } + else if (scenery.type == "text") { + this.mediaEditor.hide() + this.sculptureEditor.hide() this.textEditor.pick(scenery) } else { this.textEditor.hide() + this.sculptureEditor.hide() this.mediaEditor.pick(scenery) } }, diff --git a/public/assets/javascripts/ui/editor/SculptureEditor.js b/public/assets/javascripts/ui/editor/SculptureEditor.js new file mode 100644 index 0000000..cce000e --- /dev/null +++ b/public/assets/javascripts/ui/editor/SculptureEditor.js @@ -0,0 +1,200 @@ + +var SculptureEditor = FormView.extend({ + el: "#sculptureEditor", + + events: { + "keydown": 'taint', + "focus [name]": "clearMinotaur", + "click [data-role=play-media]": "togglePaused", + "mousedown [name=keyframe]": "stopPropagation", + "mousedown": "stopPropagation", + "change [name=keyframe]": "seek", + "change [name=autoplay]": "setAutoplay", + "change [name=loop]": "setLoop", + "change [name=mute]": "setMute", + "change [name=width]": 'changeWidth', + "change [name=height]": 'changeHeight', + "change [name=units]": 'changeUnits', + "click [data-role=destroy-media]": "destroy", + }, + + initialize: function(opt){ + this.parent = opt.parent + this.__super__.initialize.call(this) + + this.$name = this.$("[name=name]") + this.$description = this.$("[name=description]") + + // image fields + this.$width = this.$("[name=width]") + this.$height = this.$("[name=height]") + this.$units = this.$("[name=units]") + + // video fields + this.$playButton = this.$("[data-role=play-media]") + this.$autoplay = this.$("[name=autoplay]") + this.$loop = this.$("[name=loop]") + this.$mute = this.$("[name=mute]") + this.$keyframe = this.$("[name=keyframe]") + }, + + toggle: function(state) { + if (state) { + this.parent.settings.toggle() + } + this.$el.toggleClass("active", state); + }, + + togglePaused: function(state){ + var state = this.sculpture.toggle(state) + this.$playButton.toggleClass("paused", ! state) + }, + + pick: function(sculpture) { + if (this.sculpture && sculpture !== this.sculpture) { + this.unbind() + } + + this.bind(sculpture) + this.$el.addClass("active") + +// app.controller.toolbar.resetMode() + app.controller.toolbar.resetControls() + // Sculpture.resize.show(sculpture) + Sculpture.hovering = true + + var media = sculpture.media + + // console.log(media) + + this.$name.val(media.title) // || filenameFromUrl(media.url) ) + this.$description.val(media.description) + this.setDimensions() + this.$units.val( "ft" ) + + switch (media.type) { + case "image": + this.$(".video").hide() + this.$(".audio").hide() + this.$(".image").show() + break + + case "youtube": + case "vimeo": + case "video": + this.$(".image").hide() + this.$(".audio").hide() + this.$(".video").show() + + this.$playButton.toggleClass("paused", ! this.sculpture.paused()) + this.$autoplay.prop('checked', !! media.autoplay) + this.$loop.prop('checked', !! media.loop) + this.$mute.prop('checked', !! media.mute) + this.$keyframe.val( Number(media.keyframe || 0) ) + break + + case "soundcloud": + this.$(".image").hide() + this.$(".video").hide() + this.$(".audio").show() + this.$playButton.toggleClass("paused", ! this.sculpture.paused()) + this.$autoplay.prop('checked', !! media.autoplay) + this.$loop.prop('checked', !! media.loop) + break + } + }, + + hide: function(sculpture){ + if (this.sculpture) { + this.unbind() + } + this.toggle(false) + }, + + seek: function(){ + var n = parseFloat( this.$keyframe.val() ) + this.sculpture.seek(n) + this.tainted = true + + this.sculpture.media.keyframe = n + }, + setAutoplay: function(){ + var checked = this.$autoplay.prop('checked') + this.sculpture.media.autoplay = checked + this.tainted = true + if (checked && this.sculpture.paused()) { + this.togglePaused() + } + }, + setLoop: function(){ + var checked = this.$loop.prop('checked') + this.sculpture.setLoop(checked) + this.tainted = true + }, + setMute: function(){ + var checked = this.$mute.prop('checked') + this.sculpture.media.mute = checked + this.sculpture.mute(checked) + this.tainted = true + }, + + setDimensions: function(){ + if (! this.sculpture) return + this.$width.unitVal( Number(this.sculpture.naturalDimensions.a * this.sculpture.scale) || "" ) + this.$height.unitVal( Number(this.sculpture.naturalDimensions.b * this.sculpture.scale) || "" ) + this.tainted = true + }, + changeWidth: function(e){ + e.stopPropagation() + this.sculpture.set_scale( this.$width.unitVal() / this.sculpture.naturalDimensions.a ) + this.setDimensions() + }, + changeHeight: function(e){ + e.stopPropagation() + this.sculpture.set_scale( this.$height.unitVal() / this.sculpture.naturalDimensions.b ) + this.setDimensions() + }, + changeUnits: function(){ + app.units = this.$units.val() + this.$('.units').resetUnitVal() + }, + + taint: function(e){ + e.stopPropagation() + this.tainted = true + }, + + bind: function(sculpture){ + this.sculpture = sculpture + this.sculpture.mx.bound = true + this.sculpture.mx.el.classList.add("picked") + }, + + unbind: function(){ + if (this.sculpture) { + this.sculpture.focused = false + if (this.tainted && this.sculpture.media) { + this.sculpture.media.title = this.$name.val() + this.sculpture.media.description = this.$description.val() + Minotaur.watch( app.router.editorView.settings ) + } + if (this.sculpture.mx) { + this.sculpture.mx.bound = false + this.sculpture.mx.el.classList.remove("picked") + } + } + this.tainted = false + this.sculpture = null + }, + + destroy: function(){ + var sculpture = this.sculpture + this.hide() + + sculpture.remove() + + this.tainted = false + this.sculpture = null + }, + +}) diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index ca6cc94..1eda8bd 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -74,6 +74,7 @@ <script type="text/javascript" src="/assets/javascripts/rectangles/engine/scenery/types/video.js"></script> <script type="text/javascript" src="/assets/javascripts/rectangles/engine/sculpture/_sculpture.js"></script> +<script type="text/javascript" src="/assets/javascripts/rectangles/engine/sculpture/move.js"></script> <script type="text/javascript" src="/assets/javascripts/rectangles/engine/sculpture/types/_object.js"></script> <script type="text/javascript" src="/assets/javascripts/rectangles/engine/sculpture/types/image.js"></script> @@ -124,6 +125,7 @@ <script type="text/javascript" src="/assets/javascripts/ui/editor/MediaUpload.js"></script> <script type="text/javascript" src="/assets/javascripts/ui/editor/MediaViewer.js"></script> <script type="text/javascript" src="/assets/javascripts/ui/editor/Presets.js"></script> +<script type="text/javascript" src="/assets/javascripts/ui/editor/SculptureEditor.js"></script> <script type="text/javascript" src="/assets/javascripts/ui/editor/TextEditor.js"></script> <script type="text/javascript" src="/assets/javascripts/ui/editor/WallpaperPicker.js"></script> |
