From 32a87ba99dd104a839766a522e290ec61fea5edf Mon Sep 17 00:00:00 2001 From: Adam Goldsmith Date: Sun, 24 Sep 2017 16:45:51 -0400 Subject: [PATCH] Really basic client-side card generation --- js/editor.js | 77 ++ server.js | 49 +- template/card.json | 29 + template/deck.json | 44 + template/environment/card.svg | 364 +++++++ template/hero/card.svg | 1461 ++++++++++++++++++++++++++++ template/hero/charBack.svg | 99 ++ template/hero/charFront.svg | 277 ++++++ template/villain/card.svg | 1475 +++++++++++++++++++++++++++++ template/villain/character.svg | 169 ++++ template/villain/instructions.svg | 291 ++++++ 11 files changed, 4334 insertions(+), 1 deletion(-) create mode 100644 js/editor.js create mode 100644 template/card.json create mode 100644 template/deck.json create mode 100644 template/environment/card.svg create mode 100644 template/hero/card.svg create mode 100644 template/hero/charBack.svg create mode 100644 template/hero/charFront.svg create mode 100644 template/villain/card.svg create mode 100644 template/villain/character.svg create mode 100644 template/villain/instructions.svg diff --git a/js/editor.js b/js/editor.js new file mode 100644 index 0000000..dcb50d7 --- /dev/null +++ b/js/editor.js @@ -0,0 +1,77 @@ +let deckJSON; +window.addEventListener("load", () => { + let xhr = new XMLHttpRequest(); + xhr.addEventListener("load", () => { + let respSVG = xhr.responseXML.children[0]; + + document.querySelector('#jsonUpload').addEventListener('change', event => { + let files = event.target.files; + let reader = new FileReader(); + reader.onload = e => { + deckJSON = JSON.parse(e.target.result); + let newSvg = document.createElement('svg'); + document.body.appendChild(newSvg); + deckJSON.deck.forEach((card, index) => { + let cardSVG = respSVG.cloneNode(true); + cardSVG.setAttributeNS("http://www.w3.org/2000/svg", "x", index*181 + "pt"); + newSvg.appendChild(cardSVG); + for (let prop in card) { + if (prop !== "count") { + wrapSVGText(cardSVG.querySelector('#' + prop), + String(card[prop])); + } + } + }); + }; + reader.readAsText(files[0]); + }); + }); + xhr.open("GET", "/template/environment/card.svg"); + xhr.send(); +}); + +function wrapSVGText(e, string) { + // TODO: bold or italic text + e.innerHTML = ""; // clear element + let tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + e.appendChild(tspan); + let words = string.split(" "); + let line = []; + while(words.length > 0) { + let word = words.shift(); + line.push(word); + tspan.innerHTML = line.join(" "); + // horizontal overflow + // TODO: actually use units (also applies to vertical) + if (word === "\n" || + (parseFloat(e.getAttribute("width")) && + tspan.getComputedTextLength() > parseFloat(e.getAttribute("width")))) { + // if we have height, we can line wrap + if (parseFloat(e.getAttribute("height")) && + e.children.length * parseFloat(e.getAttribute('font-size')) < + parseFloat(e.getAttribute('height'))) { + words.unshift(line.pop()); + tspan.innerHTML = line.join(" "); + line = []; + + tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + tspan.setAttribute('x', e.getAttribute('x')); + tspan.setAttribute('dy', e.getAttribute('font-size')); + e.appendChild(tspan); + } + // vertical overflow or horizontal overflow with no height variable + // TODO: better with recursion instead? + else { + line = []; + e.innerHTML = ""; // remove all tspans + tspan = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + e.appendChild(tspan); + // TODO: maybe binary search font size later if I really care + e.setAttribute('font-size', parseFloat(e.getAttribute('font-size')) * 0.9); + words = string.split(" "); + console.log("resetting, size= " + e.getAttribute('font-size')); + } + } + } +} + diff --git a/server.js b/server.js index ecc0599..3281716 100644 --- a/server.js +++ b/server.js @@ -24,6 +24,9 @@ const server = http.createServer((req, res) => { case 'playfield.js': sendFile(res, 'js/playfield.js', 'application/javascript'); break; + case 'editor.js': + sendFile(res, 'js/editor.js', 'application/javascript'); + break; case 'interact.js': sendFile(res, 'interact.js', 'application/javascript'); break; @@ -31,6 +34,28 @@ const server = http.createServer((req, res) => { send404(res, uri); } break; + case 'template': + pathParts.splice(0, 2); // remove first two elements + let item = pathParts.join("/"); + console.log("template/" + item); + switch (item) { + case "card.json": + case "deck.json": + sendFile(res, "template/" + item, 'application/json'); + break; + case "environment/card.svg": + case "hero/card.svg": + case "hero/charBack.svg": + case "hero/charFront.svg": + case "villain/card.svg": + case "villain/character.svg": + case "villain/instructions.svg": + sendFile(res, "template/" + item, 'image/svg+xml'); + break; + default: + send404(res, uri); + } + break; case 'deck': if (pathParts.length === 3) { let deckName = pathParts[2]; @@ -42,6 +67,9 @@ const server = http.createServer((req, res) => { case 'play': sendPlayfield(res, deckName); break; + case 'editor': + sendEditor(res, deckName); + break; case 'deck.png': sendFile(res, deckName + '.png', 'image/png'); break; @@ -84,13 +112,32 @@ function sendDeckIndex(res, deckName) { - Play! + `; res.writeHead(200, {'Content-type': 'text/html; charset=utf-8'}); res.end(html, 'utf-8'); } +function sendEditor(res, deckName) { + const html = ` + + + + + + +
+ + + `; + res.writeHead(200, {'Content-type': 'text/html; charset=utf-8'}); + res.end(html, 'utf-8'); +} + function sendPlayfield(res, deckName) { const html = ` diff --git a/template/card.json b/template/card.json new file mode 100644 index 0000000..286db40 --- /dev/null +++ b/template/card.json @@ -0,0 +1,29 @@ +{ + "Name": "Card", + "Transform": { + "posX": 0, + "posY": 0, + "posZ": 0, + "rotX": 0, + "rotY": 0, + "rotZ": 0, + "scaleX": 1.0, + "scaleY": 1.0, + "scaleZ": 1.0 + }, + "Nickname": "", + "Description": "", + "ColorDiffuse": { + "r": 0.713235259, + "g": 0.713235259, + "b": 0.713235259 + }, + "Locked": false, + "Grid": true, + "Snap": true, + "Autoraise": true, + "Sticky": true, + "Tooltip": true, + "CardID": 0, + "SidewaysCard": false +} diff --git a/template/deck.json b/template/deck.json new file mode 100644 index 0000000..6d4fc2a --- /dev/null +++ b/template/deck.json @@ -0,0 +1,44 @@ +{ + "SaveName": "", + "GameMode": "", + "Date": "", + "Table": "", + "Sky": "", + "Note": "", + "Rules": "", + "PlayerTurn": "", + "ObjectStates": [ + { + "Name": "DeckCustom", + "Transform": { + "posX": 0, + "posY": 0, + "posZ": 0, + "rotX": 0, + "rotY": 0.0, + "rotZ": 0.0, + "scaleX": 1.0, + "scaleY": 1.0, + "scaleZ": 1.0 + }, + "Nickname": "", + "Description": "", + "ColorDiffuse": { + "r": 0.713239133, + "g": 0.713239133, + "b": 0.713239133 + }, + "Grid": true, + "Locked": false, + "SidewaysCard": false, + "DeckIDs": [], + "CustomDeck": { + "1": { + "FaceURL": "SET ME", + "BackURL": "SET ME" + } + }, + "ContainedObjects": [] + } + ] +} diff --git a/template/environment/card.svg b/template/environment/card.svg new file mode 100644 index 0000000..1c2e28d --- /dev/null +++ b/template/environment/card.svg @@ -0,0 +1,364 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + art by + + Text Here +Text Here + +Keywords + + + + + + + + + + + + + + + + + + + + +3 + +Header + + diff --git a/template/hero/card.svg b/template/hero/card.svg new file mode 100644 index 0000000..7a2ff92 --- /dev/null +++ b/template/hero/card.svg @@ -0,0 +1,1461 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Header + Keywords + + Text Here "Type Quote Here!" + - Name, Comic # + Art By + + + + + + + + + 3 + + diff --git a/template/hero/charBack.svg b/template/hero/charBack.svg new file mode 100644 index 0000000..cfa3135 --- /dev/null +++ b/template/hero/charBack.svg @@ -0,0 +1,99 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + { Text Here{ Text Here{ Text Here + diff --git a/template/hero/charFront.svg b/template/hero/charFront.svg new file mode 100644 index 0000000..4c54859 --- /dev/null +++ b/template/hero/charFront.svg @@ -0,0 +1,277 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Power name + + Power: Text Here 00 + Art By + + + + diff --git a/template/villain/card.svg b/template/villain/card.svg new file mode 100644 index 0000000..3d9d768 --- /dev/null +++ b/template/villain/card.svg @@ -0,0 +1,1475 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Header + Keywords + + Text Here "Type Quote Here!" + - Name, Comic # + Art By + + + + + + + + + 3 + + diff --git a/template/villain/character.svg b/template/villain/character.svg new file mode 100644 index 0000000..104dfef --- /dev/null +++ b/template/villain/character.svg @@ -0,0 +1,169 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Villain Title + villain + Villain Name + 000 + + Art By + + diff --git a/template/villain/instructions.svg b/template/villain/instructions.svg new file mode 100644 index 0000000..6b009ca --- /dev/null +++ b/template/villain/instructions.svg @@ -0,0 +1,291 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Villain Name + Villain Title + Art By + + Text Here + + + Text Here SetUp + + Game Play + Advanced + Text Here +