I made this two-file demo earlier today, it was really sloppy but I think it's cute enough to share.
:> index.html: <!DOCTYPE html> <head> </head> <body> </body> </html> autoexec.js: (() => { 'use strict'; /* global state hooks */ (() => { /** * sometimes we want to hook events to only get triggered once, * especially when alternating events */ if (!('once' in EventTarget.prototype)) { EventTarget.prototype.once = function(eventName, callback) { var wrappedCallback = function(e) { callback(e); this.removeEventListener(eventName, wrappedCallback); }; this.addEventListener(eventName, wrappedCallback); }; } })(); /** * avoid repeating myself by binding javascript object notation to css via get/set directly. * * */ const json_bind_css_property = function(object, aliasName, realName) { Object.defineProperty(object, aliasName, { get: function() { return this.html.style[realName]; }, set: function(setValue) { this.html.style[realName] = setValue; } }); }; const drop_handler = function(e) { console.log('unselecting.'); if (window.selectedMorph != null) { window.selectedMorph = null; } }; const css_px_to_number = (text) => { return Number(text.match(/\d+/)); } const drag_handler = function(e) { const start_x = window.startX; const start_y = window.startY; const mouse_x = e.clientX; const mouse_y = e.clientY; const selectedMorph = window.selectedMorph; const offset_x = mouse_x - start_x; const offset_y = mouse_y - start_y; const morph_start_x = window.morph_start_x; const morph_start_y = window.morph_start_y; console.log({ x1: start_x, y1: start_y, x2: mouse_x, y2: mouse_y }); selectedMorph.left = (css_px_to_number(morph_start_x) + offset_x) + 'px'; selectedMorph.top = (css_px_to_number(morph_start_y) + offset_y) + 'px'; }; const Morph = function() { var self = this; this.html = document.createElement('div'); this.html.style.position = 'absolute'; this.left = 0; this.top = 0; this.html.style.display = 'inline-block'; this.width = '50px'; this.height = '40px'; let anticipate_drop = null; let anticipate_click = null; anticipate_drop = function(e) { e.stopPropagation(); window.selectedMorph = null; window.removeEventListener('mousemove', drag_handler); self.html.once('click', anticipate_click); console.log('drop'); }; anticipate_click = function(e) { e.stopPropagation(); window.morph_start_x = self.left; window.morph_start_y = self.top; window.startX = e.clientX; window.startY = e.clientY; window.selectedMorph = self; /* once clicked, we want to have the window unselect if we click on it */ window.once('click', anticipate_drop); window.addEventListener('mousemove', drag_handler); }; /* anticipate the click of this Morph. */ this.html.once('click', anticipate_click); return this; }; Morph.prototype.openInWorld = function() { document.body.appendChild(this.html); }; Morph.prototype.delete = function() { var ref = this.get; ref.parentElement.removeChild(ref); }; Morph.new = function() { return new Morph; }; json_bind_css_property(Morph.prototype, 'color', 'backgroundColor'); json_bind_css_property(Morph.prototype, 'width', 'width'); json_bind_css_property(Morph.prototype, 'height', 'height'); json_bind_css_property(Morph.prototype, 'left', 'left'); json_bind_css_property(Morph.prototype, 'top', 'top'); window.testMe = function() { var joe = new Morph; joe.color = 'blue'; joe.openInWorld(); }; window.Morph = Morph; })(); -- View this message in context: http://forum.world.st/Fun-with-Morphs-in-JavaScript-tp4918046.html Sent from the Pharo Smalltalk Developers mailing list archive at Nabble.com.