Last active
August 31, 2020 16:30
-
-
Save spruce/ca133bd34dd3cfabbd866b20667b1a32 to your computer and use it in GitHub Desktop.
New Twiddle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Controller from '@ember/controller'; | |
import { action } from "@ember/object"; | |
import { tracked } from '@glimmer/tracking'; | |
import move from 'ember-animated/motions/move'; | |
import { inject as service } from "@ember/service"; | |
import drag from '../motions/drag'; | |
export default class ApplicationController extends Controller { | |
@service("-ea-motion") motion; | |
@tracked animators = 'click button above'; | |
appName = 'Ember Twiddle'; | |
allTodos = [createTodo(2,'todo'),createTodo(1,'todo'),createTodo(3,'todo'), | |
createTodo(4,'todo'),createTodo(5,'todo'),createTodo(6,'todo'), | |
createTodo(7,'doing'),createTodo(8,'doing'),createTodo(9,'doing')]; | |
get todo(){ | |
return this.allTodos.filterBy("state", "todo"); | |
}; | |
get sortedTodo() { | |
return this.todo.sortBy("sortPriority"); | |
}; | |
get doing(){ | |
return this.allTodos.filterBy("state", "doing"); | |
}; | |
get sortedDoing() { | |
return this.doing.sortBy("sortPriority"); | |
}; | |
@action | |
logAnimators(task) { | |
this.animators = `this.motion._animators[1].finalizeAnimation.isRunning: ${this.motion._animators[1].finalizeAnimation.isRunning}<br>this.motion._animators[3].finalizeAnimation.isRunning:${this.motion._animators[3].finalizeAnimation.isRunning}` | |
console.log(this.motion._animators[1].finalizeAnimation.isRunning); | |
console.log(this.motion._animators[3].finalizeAnimation.isRunning); | |
}; | |
@action | |
beginDragging(task, event) { | |
console.log('beginDragging', task, event); | |
let dragState; | |
let self = this; | |
function stopMouse() { | |
recalc(self.sortedTodo); | |
recalc(self.sortedDoing); | |
task.dragState = null; | |
Ember.notifyPropertyChange(task, "dragState"); | |
window.removeEventListener("mouseup", stopMouse); | |
window.removeEventListener("mousemove", updateMouse); | |
} | |
function updateMouse(event) { | |
dragState.latestPointerX = event.x; | |
dragState.latestPointerY = event.y; | |
task.dragState = dragState; | |
Ember.notifyPropertyChange(task, "dragState"); | |
} | |
dragState = new DragState({ | |
initialPointerX: event.x, | |
initialPointerY: event.y, | |
latestPointerX: event.x, | |
latestPointerY: event.y, | |
column: task.state, | |
}); | |
window.addEventListener("mouseup", stopMouse); | |
window.addEventListener("mousemove", updateMouse); | |
task.dragState = dragState; | |
Ember.notifyPropertyChange(task, "dragState"); | |
}; | |
get otherColumns(){ | |
return this._columns; | |
}; | |
_columns = []; | |
@action | |
registerColumn(element, args) { | |
setTimeout(() => {this._columns.push({ | |
name: args[0], | |
x: element.offsetLeft + element.offsetWidth / 2, | |
}); | |
this.notifyPropertyChange("otherColumns");}, 500) | |
}; | |
transition = function* (otherColumns, obj) { | |
console.log('transition') | |
let { keptSprites, receivedSprites } = obj; | |
let activeSprite = keptSprites | |
.concat(receivedSprites) | |
.find((sprite) => sprite.owner.value.dragState); | |
let others = keptSprites.filter((sprite) => sprite !== activeSprite); | |
if (activeSprite) { | |
drag(activeSprite, { | |
others, | |
otherColumns, | |
onCollision(otherSprite) { | |
console.log('collision'); | |
// same column | |
let myModel = activeSprite.owner.value; | |
let otherModel = otherSprite.owner.value; | |
let myPriority = myModel.sortPriority; | |
let theirPriority = otherModel.sortPriority; | |
// if we are not neighbors make it wonky | |
if (myPriority > theirPriority) { | |
myModel.sortPriority = theirPriority - 0.5; | |
} else { | |
myModel.sortPriority = theirPriority + 0.5; | |
} | |
Ember.notifyPropertyChange(myModel, "sortPriority"); | |
}, | |
onCollisionOther(otherColumn) { | |
console.log('onCollisionOther') | |
let myModel = activeSprite.owner.value; | |
myModel.state = otherColumn; | |
}, | |
}); | |
} | |
others.forEach(move); | |
} | |
} | |
function createTodo(num, state){ | |
return new Todo({ | |
name: state + num, | |
state, | |
id: num, | |
sortPriority: num, | |
dragState: null | |
}) | |
} | |
function sleep(ms){ | |
return new Promise((resolve) => {setTimeout(resolve, ms);}); | |
} | |
class Todo{ | |
@tracked name; | |
@tracked state; | |
@tracked id; | |
@tracked sortPriority; | |
@tracked dragState; | |
constructor(obj){ | |
this.name = obj.name; | |
this.state = obj.state; | |
this.id = obj.id; | |
this.sortPriority = obj.sortPriority; | |
this.dragState = obj.dragState; | |
} | |
} | |
class DragState{ | |
@tracked initialPointerX; | |
@tracked initialPointerY; | |
@tracked latestPointerX; | |
@tracked latestPointerY; | |
@tracked column; | |
constructor(obj){ | |
this.initialPointerX = obj.initialPointerX; | |
this.initialPointerY = obj.initialPointerY; | |
this.latestPointerX = obj.latestPointerX; | |
this.latestPointerY = obj.latestPointerY; | |
this.column = obj.column; | |
} | |
} | |
function recalc(columns) { | |
console.log(columns) | |
let counter = 1; | |
for (const task of columns) { | |
task.sortPriority = counter++; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// copied from https://github.com/ef4/living-animation/blob/master/src/ui/routes/tutorial-24/-utils/drag.js | |
import { Motion, rAF } from "ember-animated"; | |
import { next } from "@ember/runloop"; | |
export default function drag(sprite, opts) { | |
console.log('new drag'); | |
return new Drag(sprite, opts).run(); | |
} | |
class Drag extends Motion { | |
constructor(sprite, opts) { | |
super(sprite, opts); | |
this.canChange = true; | |
this.prior = null; | |
// This is our own sprite's absolute screen position that | |
// corresponds to the real start of dragging (which may span many | |
// Drag instances, because of interruption) | |
this.dragStartX = null; | |
this.dragStartY = null; | |
} | |
interrupted(motions) { | |
this.prior = motions.find((m) => m instanceof this.constructor); | |
} | |
*animate() { | |
console.log('animate', this.opts.otherColumns); | |
let sprite = this.sprite; | |
let initialTx, initialTy; | |
if (this.prior) { | |
this.dragStartX = this.prior.dragStartX; | |
this.dragStartY = this.prior.dragStartY; | |
initialTx = | |
sprite.transform.tx - | |
sprite.absoluteInitialBounds.left + | |
this.dragStartX; | |
initialTy = | |
sprite.transform.ty - | |
sprite.absoluteInitialBounds.top + | |
this.dragStartY; | |
} else { | |
this.dragStartX = sprite.absoluteInitialBounds.left; | |
this.dragStartY = sprite.absoluteInitialBounds.top; | |
initialTx = sprite.transform.tx; | |
initialTy = sprite.transform.ty; | |
} | |
// targets are all in absolute screen coordinates | |
let targets = this.opts.others.map((s) => | |
makeTarget(s.absoluteFinalBounds, s) | |
); | |
let targetCols = this.opts.otherColumns; | |
let ownTarget = makeTarget(sprite.absoluteFinalBounds, sprite); | |
let dragState = sprite.owner.value.dragState; | |
sprite.applyStyles({ | |
"z-index": "1", | |
outline: "none", | |
}); | |
while (sprite.owner.value.dragState) { | |
let dragState = sprite.owner.value.dragState; | |
// these track relative motion since the drag started | |
let dx = dragState.latestPointerX - dragState.initialPointerX; | |
let dy = dragState.latestPointerY - dragState.initialPointerY; | |
// adjust our transform to match the latest relative mouse motion | |
sprite.translate( | |
dx + initialTx - sprite.transform.tx, | |
dy + initialTy - sprite.transform.ty | |
); | |
// now this is our own absolute center position | |
let x = dx + this.dragStartX + sprite.absoluteFinalBounds.width / 2; | |
let y = dy + this.dragStartY + sprite.absoluteFinalBounds.height / 2; | |
let ownDistance = | |
(x - ownTarget.x) * (x - ownTarget.x) + | |
(y - ownTarget.y) * (y - ownTarget.y); | |
let closerTarget = targets.find((target) => { | |
let partialX = target.x - x; | |
let partialY = target.y - y; | |
let distance = partialX * partialX + partialY * partialY; | |
return distance < ownDistance; | |
}); | |
let ownXDistance = Math.abs(x - ownTarget.x); // distance to where it will animate to | |
let closerOtherColumn = targetCols.find((col) => { | |
return ( | |
col.name !== sprite.owner.value.state && | |
Math.abs(col.x - x) + 10 < ownXDistance | |
); | |
}); | |
if (closerOtherColumn) { | |
next(this, this.opts.onCollisionOther, closerOtherColumn.name); | |
} else if (closerTarget) { | |
next(this, this.opts.onCollision, closerTarget.payload); | |
} | |
yield rAF(); | |
} | |
} | |
} | |
export function makeTarget(bounds, payload) { | |
return { | |
x: bounds.left + bounds.width / 2, | |
y: bounds.top + bounds.height / 2, | |
payload, | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"version": "0.17.1", | |
"EmberENV": { | |
"FEATURES": {}, | |
"_TEMPLATE_ONLY_GLIMMER_COMPONENTS": false, | |
"_APPLICATION_TEMPLATE_WRAPPER": true, | |
"_JQUERY_INTEGRATION": true | |
}, | |
"options": { | |
"use_pods": false, | |
"enable-testing": false | |
}, | |
"dependencies": { | |
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js", | |
"ember": "3.18.1", | |
"ember-template-compiler": "3.18.1", | |
"ember-testing": "3.18.1" | |
}, | |
"addons": { | |
"@glimmer/component": "1.0.0", | |
"ember-animated": "0.10.1", | |
"@ember/render-modifiers": "1.0.2" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment