diff options
Diffstat (limited to 'scripts/cards')
-rw-r--r-- | scripts/cards/card.js | 110 | ||||
-rw-r--r-- | scripts/cards/deck.js | 146 | ||||
-rw-r--r-- | scripts/cards/drag.js | 128 |
3 files changed, 384 insertions, 0 deletions
diff --git a/scripts/cards/card.js b/scripts/cards/card.js new file mode 100644 index 0000000..750d124 --- /dev/null +++ b/scripts/cards/card.js @@ -0,0 +1,110 @@ +'use strict'; + +// Possible positions of content in a card +const CardPos = ["top", "topl", "topr", "mid", "midt", "midb", "bot", "botl", "botr", "all"]; + +// Card class represents one card. +// Every card should have a deck. +// Use deck.appendCard or deck.prependCard to make a card visible +class Card { + constructor (data) + { + this.e = document.createElement("card"); + this.generateElements(data); + this.e.style.left = "0px"; + this.e.style.top = "0px"; + } + + // Generate a card with basic text only + static generateBasicCard (data, el) + { + let t = document.createElement("carea"); + t.className = "mid"; + t.innerText = data; + el.appendChild(t); + } + + // Generate a card with a simple error message. + static generateErrorCard (el) + { + Card.generateBasicCard("Card Error: data", el); + } + + // Generate an area of a card + static generateCArea (data, carea, assetURL) + { + // Create and set area + let area = document.createElement("carea"); + area.className = carea; + + // Create inner area text and images + for (let i in data) + { + if (i == "style") + { + for (j in data.style) + area.style[j] = data.style[j]; + } + + if (data[i].type == "text") + { + let e = document.createElement("ctext"); + + e.innerText = data[i].text; + + for (let j in data[i].style) + e.style[j] = data[i].style[j]; + + area.appendChild(e); + + } + else if (data[i].type == "image") + { + let e = document.createElement("cimage"); + + e.style.backgroundImage = "url(\"" + assetURL + data[i].image + "\")"; + + for (let j in data[i].style) + e.style[j] = data[i].style[j]; + + area.appendChild(e); + } + } + + return area; + } + + // Generate a card with rich visuals + static generateObjectCard (data, el) + { + // Generate card areas. + for (let i in CardPos) + { + if (typeof data[CardPos[i]] == "object") + el.appendChild(this.generateCArea(data[CardPos[i]], CardPos[i], data.assetURL)); + } + } + + generateElements (data) + { + while(this.e.firstElementChild != null) + this.e.firstElementChild.remove(); + + switch (typeof data) + { + case "object": + Card.generateObjectCard(data, this.e); + break; + case "string": + Card.generateBasicCard(data, this.e); + break; + default: + Card.generateErrorCard(this.e); + } + } + + setPos (p) + { + this.e.style.setProperty("--cpos", p); + } +} diff --git a/scripts/cards/deck.js b/scripts/cards/deck.js new file mode 100644 index 0000000..6da24b0 --- /dev/null +++ b/scripts/cards/deck.js @@ -0,0 +1,146 @@ +'use strict'; + +// Deck class represents multiple cards. +// Can be arranged in multiple ways. +// Decks work as FIFO +class Deck { + + cards = []; + inf = false; + smode = ""; + sct = 0; + x = 0; + y = 0; + e = null; + + constructor(options = {mode: "stack", smode: "one", sct: 0, pos: [0, 0]}) + { + // View mode + // infdraw - infinite draw. always appears as if there are multiple cards + // stack - stack mode + // strip + // horizontal + // left (strip-hl) + // right (strip-hr) + // vertical + // up (strip-vu) + // down (strip-vd) + this.inf = options.mode == "infdraw"; + + // Select mode - controls what other cards are selected when one card is selected + // above - selectes cards above the selected one + // below - selects cards below the selected one + // around - selects cards above and below + // one - selects only card chosen + // all - selects all cards when card selected + this.smode = options.smode; + + // Select count (negative defaults to 0) + // above - controls number of cards above clicked are selected + // below - controls number of cards below clicked are selected + // around + // number - number above and below selected + // array - [first number: number above selected] [second number: number below selected] + // one - no effect + // all - no effect + this.sct = options.sct > 0 ? options.sct : 0; + + // Position + // array of where the deck is centered + this.x = options.pos[0]; + this.y = options.pos[1]; + + this.e = document.createElement("deck"); + this.e.style.left = this.x + "px"; + this.e.style.top = this.y + "px"; + this.e.setAttribute("mode", options.mode); + } + + updatePos() + { + let len = this.cards.length - 1; + for(let i in this.cards) + this.cards[i].setPos(len-i); + this.updateCount(); + } + + appendCard(card) + { + this.cards.push(card); + this.e.appendChild(card.e); + this.updatePos(); + + } + + prependCard(card) + { + this.cards.unshift(card); + this.e.prepend(card.e); + card.setPos(this.cards.length - 1); + this.updateCount(); + } + + addCardAt(card, index) + { + if(index < 0 || index > this.cards.length) + return + + if(index == 0) { + this.prependCard(card); + } else if (index == this.cards.length) { + this.appendCard(card); + } else { + let temp = this.cards.slice(0, index); + temp[temp.length - 1].e.after(card.e); + temp.push(card); + this.cards.unshift(...temp); + this.updatePos(); + } + } + + swapCards(index1, index2) + { + if(index1 < 0 || index1 >= this.cards.length || index2 < 0 || index2 >= this.cards.length) + return + + var temp = this.cards[index1] + this.cards[index1] = this.cards[index2]; + this.cards[index2] = temp; + + this.cards[index1 - 1].e.after(this.cards[index1]); + this.cards[index2 - 1].e.after(this.cards[index2]); + } + + removeCard(index) + { + if(index < 0 || index >= this.cards.length) + return + + this.e.removeChild(this.cards[index].e); + let c = this.cards.splice(index, 1)[0]; + + this.updatePos(); + return c; + } + + removeFront() + { + return this.removeCard(this.cards.length - 1); + } + + removeBack() + { + return this.removeCard(0); + } + + updateCount () + { + this.e.style.setProperty("--ccount", this.cards.length - 1); + } + + isInside(x, y) + { + var rect = this.e.getBoundingClientRect(); + return (x > rect.left && x < rect.right && y > rect.top && y < rect.bottom) + } +} diff --git a/scripts/cards/drag.js b/scripts/cards/drag.js new file mode 100644 index 0000000..3b02eff --- /dev/null +++ b/scripts/cards/drag.js @@ -0,0 +1,128 @@ +'use strict'; + +class MultiDrag extends EventTarget { + del = false; + drag = []; + cbs = []; + + constructor() { + super(); + + window.addEventListener("mousemove", this.update.bind(this)); + document.body.addEventListener("mouseleave", this.stopDraggingAll.bind(this)); + } + + addDragEl(el, ox, oy, px, py, pt) { + if(this.del) + return; + + el.style.transitionDuration = "0.04s"; + + this.drag.push({ + e: el, + osx: ox, + osy: oy, + prx: px, + pry: py, + ptd: pt + }); + + return this.drag.length - 1; + } + + dragging(e) { + for(let i in this.drag) { + if(this.drag[i].e == e) + return true; + } + return false; + } + + startDragging(e) { + if(this.del) + return; + + console.log(e); + + if(e.button != 0) + return; + + this.dispatchEvent(new Event("dragstart", {target: e.target})); + + return this.addDragEl( + e.target, + e.pageX - parseInt(e.target.style.left), + e.pageY - parseInt(e.target.style.top), + e.target.style.left, + e.target.style.top, + e.target.style.transitionDuration + ); + } + + stopDragging(i) { + if(this.del) + return; + + this.del = true; + + if (i < 0 || i >= this.drag.length) + return; + + var cap = {target: null, x: 0, y: 0}; + + this.drag[i].e.style.transitionDuration = this.drag[i].ptd; + + cap.x = parseInt(this.drag[i].e.style.left); + this.drag[i].e.style.left = this.drag[i].prx; + + cap.y = parseInt(this.drag[i].e.style.top); + this.drag[i].e.style.top = this.drag[i].pry; + + cap.target = this.drag.splice(i, 1).e; + + this.del = false; + + this.dispatchEvent(new Event("dragstop", cap)); + } + + stopDraggingEl(el) { + for(let d of this.drag) { + if(d.e === el) + this.stopDragging(this.drag.indexOf(d)); + } + } + + stopDraggingAll() { + if(this.del) + return; + + this.del = true; + + while (this.drag.length > 0) { + this.drag[0].e.style.transitionDuration = this.drag[0].ptd; + this.drag[0].e.style.left = this.drag[0].prx; + this.drag[0].e.style.top = this.drag[0].pry; + + this.drag.shift(); + } + + this.del = false; + + this.dispatchEvent(new Event("dragstopall")); + } + + update(e) { + for (let i = 0; i < this.drag.length && !this.del; i++) { + this.drag[i].e.style.left = e.pageX - this.drag[i].osx + "px"; + this.drag[i].e.style.top = e.pageY - this.drag[i].osy + "px"; + } + } + + addTarget(e) { + e.addEventListener("mousedown", this.startDragging.bind(this)); + e.addEventListener("mouseup", this.stopDraggingEl.apply(this, [e])) + } + + removeTarget (e) { + } +}
\ No newline at end of file |