diff --git a/src/fridge-tile.ts b/src/fridge-tile.ts index 855bec5..56435b5 100644 --- a/src/fridge-tile.ts +++ b/src/fridge-tile.ts @@ -2,21 +2,10 @@ import { LitElement, html, css } from "lit"; import { customElement } from "lit/decorators/custom-element.js"; import { property } from "lit/decorators/property.js"; import { styleMap } from "lit/directives/style-map.js"; -import { LitDragEvent, LitDraggable } from "./lit-draggable.js"; - -export function bound(_target: unknown, key: string, descriptor: PropertyDescriptor): PropertyDescriptor { - if (typeof descriptor?.value !== "function") { - throw new Error("Only methods can be @bound."); - } - return { - configurable: true, - get() { - const method = descriptor.value.bind(this); - Object.defineProperty(this, key, { value: method, configurable: true, writable: true }); - return method; - }, - }; -} +import { ref, createRef, Ref } from "lit/directives/ref.js"; +import { LitDraggable } from "./lit-draggable.js"; +import { LitDragEvent } from "./types.js"; +import { LitDragStart, LitDragEnd } from "./lit-events.js"; @customElement("fridge-tile") export class FridgeTile extends LitElement { @@ -25,6 +14,13 @@ export class FridgeTile extends LitElement { dragHandle: LitDraggable; + transform = { + rotate: Math.random() * 30 - 15, + scale: 1.0, + }; + + handle: Ref = createRef(); + static get styles() { return css` :host { @@ -52,6 +48,9 @@ export class FridgeTile extends LitElement { position: relative; background: white; z-index: 100; + transition-property: transform; + transition-duration: 200ms; + transition-timing-function: ease-in-out; //other options are ease } .word.dragging { @@ -64,17 +63,35 @@ export class FridgeTile extends LitElement { super(); this.dragHandle = new LitDraggable(this); this.onDragEnd = this.onDragEnd.bind(this); - this.addEventListener("lit-drag-end", this.onDragEnd); + this.onDragStart = this.onDragStart.bind(this); + this.addEventListener(LitDragEnd.eventName, this.onDragEnd); + this.addEventListener(LitDragStart.eventName, this.onDragStart); } onDragEnd(ev: LitDragEvent) { + this.transform = { scale: 1.0, rotate: Math.random() * 30 - 15 }; + this.handle.value!.style.setProperty( + "transform", + `scale(${+this.transform.scale}) rotate(${+this.transform.rotate}deg)` + ); this.style.setProperty("top", `${+ev.offsetY}px`); this.style.setProperty("left", `${+ev.offsetX}px`); } + onDragStart(_ev: LitDragEvent) { + this.transform = { scale: 1.3, rotate: Math.random() * 30 - 15 }; + this.handle.value!.style.setProperty( + "transform", + `scale(${+this.transform.scale}) rotate(${+this.transform.rotate}deg)` + ); + } + render() { - const styles = styleMap({ width: `${this.word.length}ch` }); - return html`
${this.word}
`; + const styles = { + width: `${this.word.length}ch`, + transform: `rotate(${this.transform.rotate}deg)`, + }; + return html`
${this.word}
`; } } diff --git a/src/sat.ts b/src/sat.ts new file mode 100644 index 0000000..9d6b03a --- /dev/null +++ b/src/sat.ts @@ -0,0 +1,143 @@ +// Copyright (c) 2012 Elf M. Sternberg +// +// Much of the code here I would never have understood if it hadn't +// been for the patient work of Caleb Helbling +// (http://www.propulsionjs.com/), as well as the Wikipedia pages for +// the Separating Axis Theorem. It took me a week to wrap my head +// around these ideas. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +class Vector { + x: number; + y: number; + + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } + + add: (v2: Vector) { + return new Vector(this.x + v2.x, this.y + v2.y); + } + + + + add: function (v1, v2) { + return { + x: v1.x + v2.x, + y: v1.y + v2.y, + }; + }, + scalar: function (v, s) { + return { + x: v.x * s, + y: v.y * s, + }; + }, + dot: function (v1, v2) { + return v1.x * v2.x + v1.y * v2.y; + }, + magnitude2: function (v) { + var x, y; + x = v.x; + y = v.y; + return x * x + y * y; + }, + magnitude: function (v) { + return Math.sqrt(Math.vector.magnitude2(v)); + }, + normalize: function (v) { + var mag; + mag = Math.vector.magnitude(v); + return { + x: v.x / mag, + y: v.y / mag, + }; + }, + leftNormal: function (v) { + return { + x: -v.y, + y: v.x, + }; + }, +}; + + this.colliding = function (shape1, shape2) { + var axes, axes1, axes2, axis, genAxes, genProjection, j, len, proj1, proj2; + genAxes = function (shape) { + var axis, i, j, ref, results; + if (shape.length < 3) { + throw "Cannot handle non-polygons"; + } + axis = function (shape, pi) { + var edge, p1, p2; + p1 = shape[pi]; + p2 = shape[pi === shape.length - 1 ? 0 : pi + 1]; + edge = { + x: p1.x - p2.x, + y: p1.y - p2.y, + }; + return Math.vector.normalize(Math.vector.leftNormal(edge)); + }; + results = []; + for (i = j = 0, ref = shape.length; 0 <= ref ? j < ref : j > ref; i = 0 <= ref ? ++j : --j) { + results.push(axis(shape, i)); + } + return results; + }; + genProjection = function (shape, axis) { + var i, j, max, min, p, ref; + min = Math.vector.dot(axis, shape[0]); + max = min; + for (i = j = 1, ref = shape.length; 1 <= ref ? j < ref : j > ref; i = 1 <= ref ? ++j : --j) { + p = Math.vector.dot(axis, shape[i]); + if (p < min) { + min = p; + } + if (p > max) { + max = p; + } + } + return { + min: min, + max: max, + }; + }; + axes1 = genAxes(shape1); + axes2 = genAxes(shape2); + axes = axes1.concat(axes2); + for (j = 0, len = axes.length; j < len; j++) { + axis = axes[j]; + proj1 = genProjection(shape1, axis); + proj2 = genProjection(shape2, axis); + if ( + !( + (proj1.min >= proj2.min && proj1.min <= proj2.max) || + (proj1.max >= proj2.min && proj1.max <= proj2.max) || + (proj2.min >= proj1.min && proj2.min <= proj1.max) || + (proj2.max >= proj1.min && proj2.max <= proj1.max) + ) + ) { + return false; + } + } + return true; + }; +}).call(this);