代码: 全选
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ejtile91</title>
</head>
<body>
<p><style>
#etmainouter {position: relative;}
#etmain {width: 100%; display: block;}
#trbutton {position: absolute; top: 0; right: 0; -webkit-user-select:none; -moz-user-select:none; -ms-user-select:none; user-select:none; font-size: 16px; color: #333; line-height: 20px;}
#trbutton span {cursor: pointer; display: inline-block; width: 16px; height: 16px; line-height: 16px; text-align: center;}
.etbtnline {margin: 7px 0;}
.btndotend {margin-left: 36px;}
.dcshort {width: 24px;}
.ilblk {display: inline-block;}
.hide {display: none;}
</style></p>
<div id="etmainouter">
<svg id="etmain" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" width="480" height="480">
<defs mode="0" rotatesnap="0" rotatestart="0" rotatestep="60" snapto="0" slopetype="int">
<g id="tile0" frontfill="#ececec" backfill="#54b0e8">
<path d="M 0,15.588 L -9,31.176 L -27,31.176 L -45,31.176 L -54,15.588 L -27,0 L -27,-31.176 L -9,-31.176 L 0,-46.764 L 27,-31.176 L 27,0 L 45,0 L 54,15.588 L 27,31.176 Z"/>
</g>
<g id="tile1" frontfill="#f9d98d" backfill="#d25e5e">
<path d="M 0,31.177 L -27,46.765 L -36,31.177 L -27,15.588 L -54,0 L -54,-31.177 L -36,-31.177 L -27,-15.588 L 0,-31.177 L 27,-15.588 L 54,0 L 54,31.177 L 36,31.177 L 27,46.765 Z"/>
</g>
</defs>
</svg>
<div id="trbutton">
<span onclick="undo()" id="ejtileundo" style="color: #777;"> ↶ </span>
<span onclick="redo()" id="ejtileredo" style="color: #777;"> ↷ </span>
<br>
<span onclick="scaleButton(1)" id="scaleUp"> ⊕ </span>
<span onclick="scaleButton(0)" id="scaleDown"> ⊖ </span>
<span style="display: none;" id="displayscale"></span>
<br>
<span onclick="downloadSVG()"> ⍗ </span>
<span onclick="uploadSVG()"> ⍐ </span>
</div>
</div>
<div>
<div id="defaultbtn">
</div>
<div id="settingarea" class="hide">
<div class="editsetting">
<div class="etbtnline">
<button id="rotateSnapButton" type="button" onclick="toggleRotateSnap()">rotate snap</button>
<span id="rotateSnapStartTXT" onclick="changeRotateStart()">start <span id="rotateSnapStartValue"></span></span>
<span id="rotateSnapStepTXT" onclick="changeRotateStep()">step <span id="rotateSnapStepValue"></span></span>
</div>
<div class="etbtnline">
<span>snap to </span>
<label for="snapto0"><input type="radio" name="snapto" id="snapto0" value="0" onchange="setSnapTo(this.value)" checked> side </label>
<label for="snapto1"><input type="radio" name="snapto" id="snapto1" value="1" onchange="setSnapTo(this.value)"> dot </label>
</div>
<div class="etbtnline">
<button class="btnconstruct" type="button">construct</button>
</div>
<div class="etbtnline">
<button class="btnnew" type="button">new</button>
<button class="btnedit" type="button">edit</button>
<button class="btnup" type="button">up</button>
<button class="btndown" type="button">down</button>
<button class="btndelete" type="button">delete</button>
<button class="btncopy" type="button">copy</button>
</div>
<div class="etbtnline">
<button class="btndotstart" type="button">x,y</button>
<button class="btndotend" type="button">x,y</button>
</div>
<div class="etbtnline">
<label for="dotcalculate">
<input type="radio" name="dotcalculate" value="0" checked>
<input id="dcuxi" class="dcshort" type="input">
+
<input id="dcuxsi" class="dcshort" type="input">
√
<input id="dcuxs" class="dcshort" type="input">
,
<input id="dcuyi" class="dcshort" type="input">
+
<input id="dcuysi" class="dcshort" type="input">
√
<input id="dcuys" class="dcshort" type="input">
</label>
</div>
<div class="etbtnline">
<label for="dotcalculate">
<input type="radio" name="dotcalculate" value="1">
<input id="dcuxr" class="dcshort" type="input">
° ;
<input id="dcuyi" class="dcshort" type="input">
+
<input id="dcuysi" class="dcshort" type="input">
√
<input id="dcuys" class="dcshort" type="input">
</label>
</div>
</div>
</div>
<div class="etbtnline">
<button id="settingbtn" type="button" onclick="toggleEditTiles()">setting</button>
</div>
</div>
<p><script>
// handle
var etmain, etdefs, etdrop, etwait;
var tilewaiting = document.getElementsByClassName("tilewaiting");
var tilemoving = document.getElementsByClassName("tilemoving");
var tilesnapped = document.getElementsByClassName("tilesnapped");
var tiledropped = document.getElementsByClassName("tiledropped");
var rotatecirlce = document.getElementsByClassName("rotatecirlce");
var waitactive = document.getElementsByClassName("waitactive");
const scaleUp = document.getElementById("scaleUp");
const scaleDown = document.getElementById("scaleDown");
const btnundo = document.getElementById("ejtileundo");
const btnredo = document.getElementById("ejtileredo");
const defaultbtn = document.getElementById("defaultbtn");
const settingbtn = document.getElementById("settingbtn");
const settingarea = document.getElementById("settingarea");
const rsbtn = document.getElementById("rotateSnapButton");
const rsstart = document.getElementById("rotateSnapStartValue");
const rsstep = document.getElementById("rotateSnapStepValue");
// static data
const rotatepadding = 20;
const currentscale = 0.12;
const snapratio = 2 / 3;
const snapradian = 24;
const snapradius = 0.01;
const clicktime = 777;
const clickradius = 144;
const snapdotradius = 12;
const history_length = 24;
const colormove = "#436";
const colorsnap = "green";
const colordrop = "#777";
const strokewidthmove = 4;
const strokewidthdrop = 2;
// tile data
var dotmax, dotaver;
var dotxy, dotmid, dotlen, dotslope;
// state
// 1 move drop, 2 move tile, 3 rotate tile, 4 two figure
// -1 edit tiles
var state = 0;
// mode
// 0 drop mode, 1 move mode
var mode = 0;
// mouse cursor
var startx, starty, startr, starttime;
var runx, runy;
var endx, endy, endtime;
var start2x, start2y, run2x, run2y;
var clickt, clickm, lastclickt, lastclickm;
var doubleclick = false;
// element attribute
var dropx = 0, dropy = 0, drops = 1;
var movex = 0, movey = 0, mover = 0, moven = 0, movef = 1;
// history
var history_array = new Array(history_length).fill("");
var history_point = 0, history_start = 0, history_end = 0;
// window onload
window.addEventListener("load", function () {
etinit();
// record history
history_array[history_point] = etmain.outerHTML;
});
// button START
// toggleEditTiles
function toggleEditTiles () {
// back to default
if (-1 == state) {
state = 0;
settingbtn.innerHTML = "setting";
settingarea.classList.add("hide");
defaultbtn.classList.remove("hide");
}
// setting
else {
state = -1;
settingbtn.innerHTML = "finish setting";
settingarea.classList.remove("hide");
defaultbtn.classList.add("hide");
}
};
// change rotate step
function changeRotateStep () {
let stepvalue = prompt("Input the new step degree:");
if (null == stepvalue) return;
stepvalue = parseInt(stepvalue);
if (stepvalue >= 0 && stepvalue <= 180) {
setRotateStep(stepvalue);
} else {
alert("The new step degree must between 0 to 180");
}
};
// change rotate start
function changeRotateStart () {
let startvalue = prompt("Input the new start degree:");
if (null == startvalue) return;
startvalue = parseInt(startvalue);
if (startvalue >= -90 && startvalue <= 90) {
setRotateStart(startvalue);
} else {
alert("The new start degree must between -90 to 90");
}
};
// toggle rotate snap
function toggleRotateSnap () {
if (getRotateSnap()) {
setRotateSnap(0);
} else {
setRotateSnap(1);
}
};
// download
function downloadSVG () {
let etmainclone = etmain.cloneNode(true);
let etmaincwait = etmainclone.querySelector(".etwait");
etmaincwait.setAttribute("display", "none");
let data = etmainclone.outerHTML;
let file = new Blob([data], {type: "data:image/svg+xml"});
let ejrealdl = document.createElement("a");
ejrealdl.href = URL.createObjectURL(file);
ejrealdl.download = "ejtile.svg";
ejrealdl.click();
ejrealdl.remove();
};
// testupload
function uploadSVG () {
let ejuploadinput = document.getElementsByClassName("ejuploadinput")[0];
ejuploadinput.click();
};
// scale Button
function scaleButton (uod = 1) {
let dropsbk = drops;
if (uod) {
drops = round3(drops + currentscale);
} else {
drops = round3(drops - currentscale);
}
if (drops < 0 || drops > 4) {
drops = dropsbk;
}
dropx = 0 - (0 - dropx) * drops / dropsbk;
dropy = 0 - (0 - dropy) * drops / dropsbk;
setDropXY(dropx, dropy);
setDropScale(drops);
setDropTransform();
};
// toggleScaleUp
function toggleScaleUp () {
scaleButton(true);
};
// toggleScaleDown
function toggleScaleDown () {
scaleButton(false);
};
// record history
function recordHistory () {
if (etmain.outerHTML == history_array[history_point]) return;
if (history_point + 1 < history_length) {
history_point++;
} else {
history_point = 0;
}
history_end = history_point;
if (history_start == history_end) {
history_start++;
if (history_start == history_length) {
history_start = 0;
}
}
history_array[history_point] = etmain.outerHTML;
btnundo.style.color = "#333";
btnredo.style.color = "#777";
};
// undo
function undo () {
if (history_point != history_start) {
if (history_point - 1 < 0) {
history_point = history_length - 1;
} else {
history_point = history_point - 1;
}
}
btnredo.style.color = "#333";
if (history_point == history_start) {
btnundo.style.color = "#777";
} else {
btnundo.style.color = "#333";
}
let dropxbk = dropx, dropybk = dropy, dropsbk = drops;
let movenbk = moven, movefbk = movef, moverbk = mover;
etmain.outerHTML = history_array[history_point];
etinit();
setDropXY(dropxbk, dropybk);
setDropScale(dropsbk);
setDropTransform();
if (tilemoving.length) return;
setMoveNumber(movenbk);
setMoveFlip(movefbk);
setMoveRotate(moverbk);
setMoveTransform();
};
// redo
function redo () {
if (history_point != history_end) {
if (history_point + 1 == history_length) {
history_point = 0;
} else {
history_point++;
}
}
btnundo.style.color = "#333";
if (history_point == history_end) {
btnredo.style.color = "#777";
} else {
btnredo.style.color = "#333";
}
let dropxbk = dropx, dropybk = dropy, dropsbk = drops;
let movenbk = moven, movefbk = movef, moverbk = mover;
etmain.outerHTML = history_array[history_point];
etinit();
setDropXY(dropxbk, dropybk);
setDropScale(dropsbk);
setDropTransform();
if (tilemoving.length) return;
setMoveNumber(movenbk);
setMoveFlip(movefbk);
setMoveRotate(moverbk);
setMoveTransform();
};
// button END
// get and set START
// get slope type
function getSlopeType () {
if (etdefs.hasAttribute("slopetype")) {
return etdefs.getAttribute("slopetype");
}
return "int";
};
// set slope type
function setSlopeType (v) {
etdefs.setAttribute("slopetype", v);
};
// get Wait Rotate
function getTileWaitRotate () {
let waittransform = tilewaiting[moven].getAttribute("transform");
let waittilef = waittransform.replace(/.*rotate\((.*?)\).*/, "$1");
return parseFloat(waittilef);
};
// get Wait Flip
function getTileWaitFlip () {
let waittransform = tilewaiting[moven].getAttribute("transform");
let waittilef = waittransform.replace(/.*scale\((.*?),.*/, "$1");
if (parseFloat(waittilef) < 0) {
return -1;
}
return 1;
};
// get Wait stroke-width
function getWaitStrokeWidth (waitscale, width) {
return width / waitscale;
};
// get Wait scale
function getWaitScale (n) {
return 36 / (dotmax[n] * 2);
};
// get snap to
function getSnapTo () {
if (etdefs.hasAttribute("snapto")) {
return parseInt(etdefs.getAttribute("snapto"));
}
return 0;
};
// set snap to
function setSnapTo (v) {
etdefs.setAttribute("snapto", v);
};
// get rotate snap
function getRotateSnap () {
if (etdefs.hasAttribute("rotatesnap")) {
let rotatesnap = etdefs.getAttribute("rotatesnap");
return parseInt(rotatesnap);
}
return 0;
};
// set rotate snap
function setRotateSnap (snap) {
etdefs.setAttribute('rotatesnap', snap);
if (snap) {
rsbtn.innerHTML = "[rotate snap]";
setMoveRotate(getRotateStart() * movef);
setMoveTransform();
cancelSnap();
} else {
rsbtn.innerHTML = "rotate snap";
}
};
// get rotate start
function getRotateStart () {
if (etdefs.hasAttribute("rotatestart")) {
let rotatestart = etdefs.getAttribute("rotatestart");
return parseInt(rotatestart);
}
return 0;
};
// set rotate start
function setRotateStart (start) {
etdefs.setAttribute('rotatestart', start);
rsstart.innerHTML = start;
if (getRotateSnap()) {
setMoveRotate(start);
setMoveTransform();
cancelSnap();
}
};
// get rotate step
function getRotateStep () {
if (etdefs.hasAttribute("rotatestep")) {
let rotatestep = etdefs.getAttribute("rotatestep");
return parseInt(rotatestep);
}
return 0;
};
// set rotate step
function setRotateStep (step) {
etdefs.setAttribute('rotatestep', step);
rsstep.innerHTML = step;
};
// get drop tile number
function getDropTileNumber (droppedtile) {
if (droppedtile.hasAttribute("href")) {
let etdrophref = droppedtile.getAttribute("href");
return parseInt(etdrophref.replace("#tile", ""));
}
return 0;
};
// get drop tile flip
function getDropTileFlip (droppedtile) {
if (droppedtile.hasAttribute("transform")) {
let droptiletransform = droppedtile.getAttribute("transform");
let droptilef = droptiletransform
.replace(/.*scale\((.*?),.*/, "$1");
return parseInt(droptilef);
}
return 1;
};
// get drop tile rotate
function getDropTileRotate (droppedtile) {
if (droppedtile.hasAttribute("transform")) {
let droptiletransform = droppedtile.getAttribute("transform");
let droptiler = droptiletransform
.replace(/.*rotate\((.*?)\).*/, "$1");
return parseFloat(droptiler);
}
return 0;
};
// get drop tile xy
function getDropTileXY (droppedtile) {
if (droppedtile.hasAttribute("transform")) {
let etdroptransform = droppedtile.getAttribute("transform");
let dropxy = etdroptransform
.replace(/.*translate\((.*?)\).*/, "$1");
let dropxyarr = dropxy.split(",");
return [parseFloat(dropxyarr[0]), parseFloat(dropxyarr[1])];
}
return [0, 0];
};
// getDrop transform
function getDropTransform () {
if (etdrop.hasAttribute('transform')) {
return etdrop.getAttribute('transform');
}
return "";
};
// setDrop transform
function setDropTransform (x = dropx, y = dropy, s = drops) {
etdrop.setAttribute('transform',
'translate(' + x + ',' + y + ') ' +
'scale(' + s + ')'
);
};
// getDropXY
function getDropXY () {
return getDropTileXY(etdrop);
};
// setDropXY
function setDropXY (x, y) {
dropx = round3(x);
dropy = round3(y);
};
// getDropScale
function getDropScale () {
if (etdrop.hasAttribute("transform")) {
let etdroptransform = getDropTransform();
let getdrops = etdroptransform
.replace(/.*scale\((.*?)\).*/, "$1");
return round3(parseFloat(getdrops));
}
return 1;
};
// setDropScale
function setDropScale (v) {
drops = round3(v);
document.getElementById("displayscale").innerHTML = drops;
};
// get move transform
function getMoveTransform () {
if (tilemoving.length && tilemoving[0].hasAttribute('transform')) {
return tilemoving[0].getAttribute('transform');
}
return "";
};
// set move transform
function setMoveTransform (x = movex, y = movey, f = movef, r = mover) {
if (tilemoving.length) {
tilemoving[0].setAttribute('transform',
'translate(' + x + ',' + y + ') ' +
'scale(' + f + ',1) ' +
'rotate(' + r + ')'
);
// tilewaiting transform
let waitscale = getWaitScale(moven);
tilewaiting[moven].setAttribute('transform',
'translate(' + 20 + ',' + (20 + moven * 40) + ') ' +
'scale(' + (f * waitscale) + ',' + (waitscale) + ') ' +
'rotate(' + r + ')'
);
}
};
// get movexy
function getMoveXY () {
if (tilemoving.length) {
let etmovetransform = getMoveTransform();
let movexy = etmovetransform
.replace(/.*translate\((.*?)\).*/, "$1");
let movexyarr = movexy.split(",");
let movexyarrx = round3(parseFloat(movexyarr[0]));
let movexyarry = round3(parseFloat(movexyarr[1]));
return [movexyarrx, movexyarry];
}
return [0, 0];
};
// set movexy
function setMoveXY (x, y) {
if (tilemoving.length) {
movex = round3(x);
movey = round3(y);
}
};
// get move rotate
function getMoveRotate () {
if (tilemoving.length) {
let etmovetransform = getMoveTransform();
let etmovescale = etmovetransform
.replace(/.*rotate\((.*?)\).*/, "$1");
return parseFloat(etmovescale);
}
return 0;
};
// set move rotate
function setMoveRotate (r) {
mover = round3(degree180(r));
};
// get move flip
function getMoveFlip () {
if (tilemoving.length) {
let etmovetransform = getMoveTransform();
let etmovescale = etmovetransform
.replace(/.*scale\((.*?),.*/, "$1");
return parseFloat(etmovescale);
}
return 1;
};
// set move flip
function setMoveFlip (f) {
movef = parseInt(f);
};
// get move number
function getMoveNumber () {
if (tilemoving.length) {
let movehref = tilemoving[0].getAttribute("href");
return parseInt(movehref.replace("#tile", ""));
}
return 0;
};
// set move number
function setMoveNumber (n = moven) {
moven = parseInt(n);
if (tilemoving.length) {
tilemoving[0].setAttribute("href", "#tile" + moven);
}
toggleWaitActive(n);
};
// get and set END
// standard START
// create circle
// createCircle(mx, my, 3, "blue").classList.add("testcenter");
/*
// remove testcenter
let testcenter = document.getElementsByClassName("testcenter");
while (testcenter.length) {
testcenter[0].remove();
}
*/
function createCircle (x, y, radius, fill = "transparent",
stroke = "none", sw = 7, layer = "d") {
let rocle = document.createElementNS(
'http://www.w3.org/2000/svg', 'circle');
rocle.setAttribute("r", radius);
rocle.setAttribute("cx", x);
rocle.setAttribute("cy", y);
rocle.setAttribute("fill", fill);
rocle.setAttribute("stroke", stroke);
rocle.setAttribute("stroke-width", sw);
if ("m" == layer) {
etmain.appendChild(rocle);
} else if ("d" == layer) {
etdrop.appendChild(rocle);
}
return rocle;
};
// create tile
function createTile (n = 0, x = 0, y = 0, f = 1, r = 0,
fill = "blue", stroke = colormove, sw = strokewidthmove, layer = etdrop) {
let tile = document.createElementNS(
"http://www.w3.org/2000/svg", "use");
tile.setAttribute("href", "#tile" + n);
tile.setAttribute("fill", fill);
tile.setAttribute("stroke", stroke);
tile.setAttribute("stroke-width", sw);
tile.setAttribute("transform",
"translate(" + x + "," + y + ") " +
'scale(' + f + ',1) ' +
"rotate(" + r + ")"
);
layer.appendChild(tile);
return tile;
};
// degree 180
function degree180 (r) {
if (r > 180) {
r = r - 360;
} else if (r <= -180) {
r = r + 360;
}
return round3(r);
};
// math round 1000
function round3 (num) {
return Math.round(num * 1000) / 1000;
};
// standard END
// mouse START
// ejtileWaitClick
function ejtileWaitClick (e) {
if (state != -1) {
let moden;
for (let i = 0; i < tilewaiting.length; i++) {
if (
tilewaiting[i] == e.target ||
(null != e.target.nextElementSibling &&
tilewaiting[i] == e.target.nextElementSibling)
) {
if (mode) {
moden = i;
}
else {
setMoveNumber(i);
setMoveFlip(getTileWaitFlip());
setMoveRotate(getTileWaitRotate());
if (tilemoving.length) {
tilemoving[0].setAttribute('fill', getTileFill());
setMoveTransform();
}
}
}
}
if (mode) {
// remove tilemoving
if (tilemoving.length) {
tilemoving[0].removeAttribute("stroke");
tilemoving[0].removeAttribute("stroke-width");
tilemoving[0].classList.add("tiledropped");
tilemoving[0].classList.remove("tilemoving");
}
// add tilemoving
for (let i = 0; i < tiledropped.length; i++) {
if (moden == getDropTileNumber(tiledropped[i])) {
let modet = tiledropped[i];
modet.setAttribute("stroke", colormove);
modet.setAttribute("stroke-width", strokewidthmove);
modet.classList.remove("tiledropped");
modet.classList.add("tilemoving", "wait2move");
while (modet != etdrop.lastChild) {
etdrop.insertBefore(etdrop.lastChild, modet);
}
let movexy = getMoveXY();
mover = getMoveRotate();
setMoveXY(movexy[0], movexy[1]);
setMoveNumber(getMoveNumber());
}
}
}
}
};
// mouse wheel
function ejtileMouseWheel (e) {
e.preventDefault();
let dropsbk = drops;
drops = e.deltaY * -0.01 + drops;
if (drops < 0 || drops > 4) {
drops = dropsbk;
}
let movetox = e.offsetX - (e.offsetX - dropx) * drops / dropsbk;
let movetoy = e.offsetY - (e.offsetY - dropy) * drops / dropsbk;
// set drop value
setDropXY(movetox, movetoy);
setDropScale(drops);
setDropTransform();
};
// set end xy
function setEndXY (e) {
if (ifNotGaming()) return;
// PC client
if (e.offsetX) {
endx = e.offsetX;
endy = e.offsetY;
}
// mobile client
if (e.touches) {
let ejtile_rect = etmain.getBoundingClientRect();
let rtx = e.changedTouches[0].pageX - ejtile_rect.x - window.scrollX;
let rty = e.changedTouches[0].pageY - ejtile_rect.y - window.scrollY;
endx = Math.round(rtx);
endy = Math.round(rty);
}
};
// set start xy
function setStartXY (e) {
// PC client
if (e.offsetX) {
startx = e.offsetX;
starty = e.offsetY;
}
// mobile client
if (e.touches) {
let ejtile_rect = etmain.getBoundingClientRect();
if (e.touches.length > 2) {
state = 0;
}
if (e.touches.length > 1) {
let rtx = e.touches[1].pageX - ejtile_rect.x - window.scrollX;
let rty = e.touches[1].pageY - ejtile_rect.y - window.scrollY;
run2x = start2x = Math.round(rtx);
run2y = start2y = Math.round(rty);
// set dropxy
let movetox = round3(runx - startx + dropx);
let movetoy = round3(runy - starty + dropy);
setDropXY(movetox, movetoy);
}
if (e.touches.length > 0) {
let rtx = e.touches[0].pageX - ejtile_rect.x - window.scrollX;
let rty = e.touches[0].pageY - ejtile_rect.y - window.scrollY;
runx = startx = Math.round(rtx);
runy = starty = Math.round(rty);
}
}
};
// set run XY
function setRunXY (e) {
if (ifNotGaming()) return;
// PC client
if (e.offsetX) {
runx = e.offsetX;
runy = e.offsetY;
}
// mobile client
if (e.touches) {
let ejtile_rect = etmain.getBoundingClientRect();
let rectx = ejtile_rect.x + window.scrollX;
let recty = ejtile_rect.y + window.scrollY;
if (e.touches.length > 1) {
let rtx = e.touches[1].pageX - rectx;
let rty = e.touches[1].pageY - recty;
run2x = Math.round(rtx);
run2y = Math.round(rty);
if (
e.touches[1].pageX < rectx ||
e.touches[1].pageY < recty ||
e.touches[1].pageX > ejtile_rect.width + rectx ||
e.touches[1].pageY > ejtile_rect.height + recty
) {
ejtileMouseUp(e);
}
}
if (e.touches.length > 0) {
let rtx = e.touches[0].pageX - rectx;
let rty = e.touches[0].pageY - recty;
runx = Math.round(rtx);
runy = Math.round(rty);
if (
e.touches[0].pageX < rectx ||
e.touches[0].pageY < recty ||
e.touches[0].pageX > ejtile_rect.width + rectx ||
e.touches[0].pageY > ejtile_rect.height + recty
) {
ejtileMouseUp(e);
}
}
}
};
// set state
function addNewTile () {
if (ifNotGaming()) return;
if (
mode == 0 &&
!tilemoving.length && clickt == etmain && !doubleclick
) {
movex = (startx - dropx) / drops;
movey = (starty - dropy) / drops;
createTile(moven, movex, movey, movef, mover, getTileFill())
.classList.add("tilemoving");
setMoveXY(movex, movey);
setMoveRotate(mover);
state = 2; // move tile
}
};
// moveTileEnd
function moveTileEnd () {
if (tilemoving.length && state == 2) {
let movetox = endx - startx + movex * drops;
let movetoy = endy - starty + movey * drops;
movetox = movetox / drops;
movetoy = movetoy / drops;
setMoveXY(movetox, movetoy);
}
};
// rotateSnap
function rotateSnap (rvalue) {
if (getRotateSnap()) {
let rotatestart = getRotateStart() * movef;
let rotatestep = getRotateStep();
let rn = Math.floor((rvalue - rotatestart) / rotatestep);
if (
rvalue - (rn * rotatestep + rotatestart) <
((rn + 1) * rotatestep + rotatestart) - rvalue
) {
rvalue = rn * rotatestep + rotatestart;
} else {
rvalue = (rn + 1) * rotatestep + rotatestart;
}
}
return rvalue;
};
// rotateTileEnd
function rotateTileEnd () {
if (tilemoving.length && state == 3) {
let centerx = movex * drops + dropx;
let centery = movey * drops + dropy;
let dx = endx - centerx;
let dy = endy - centery;
let endr = Math.atan2(dy, dx) / Math.PI * 180;
endr = degree180((endr - startr) * movef + mover);
// rotate snap
endr = rotateSnap(endr);
setMoveRotate(endr);
while (rotatecirlce.length) {
rotatecirlce[0].remove();
}
}
};
// rotateTile
function rotateTile () {
if (tilemoving.length && state == 3) {
let centerx = movex * drops + dropx;
let centery = movey * drops + dropy;
let dx = runx - centerx;
let dy = runy - centery;
let runr = Math.atan2(dy, dx) / Math.PI * 180;
runr = (runr - startr) * movef + mover;
// rotate snap
runr = rotateSnap(runr);
// rotate
setMoveTransform(movex, movey, movef, runr);
}
};
// moveTile
function moveTile () {
if (tilemoving.length && state == 2) {
let movetox = runx - startx + movex * drops;
let movetoy = runy - starty + movey * drops;
movetox = round3(movetox / drops);
movetoy = round3(movetoy / drops);
setMoveTransform(movetox, movetoy, movef, mover);
}
};
// set state by distance
function setState () {
let centerx = movex * drops + dropx;
let centery = movey * drops + dropy;
let dx = startx - centerx;
let dy = starty - centery;
let dxy = Math.sqrt(dx * dx + dy * dy);
// move tile
if (dxy < dotaver[moven] * drops) {
state = 2;
}
// rotate tile
else if (dxy < dotmax[moven] * drops) {
state = 3;
}
// move etdrop
else {
state = 1;
}
}
// setStartValue
function setStartValue (e) {
if (ifNotGaming()) return;
// mobile client two figures
if (e.touches && e.touches.length == 2 && state == 1) {
state = 4;
return;
}
// doubleclick
doubleclick = false;
if (Date.now() - starttime < clicktime &&
Math.pow(endx - startx, 2) + Math.pow(endy - starty, 2) < clickradius
) {
doubleclick = true;
}
// start value
starttime = Date.now();
lastclickt = clickt;
clickt = e.target;
lastclickm = clickm;
clickm = tilemoving.length + tilesnapped.length;
// state
if (
clickt.classList.contains("tilewaiting") ||
(null != clickt.nextElementSibling &&
clickt.nextElementSibling.classList.contains("tilewaiting"))
) {
state = 0;
} else if (tilemoving.length) {
setState();
} else {
state = 1;
}
};
// scaleDropEnd
function scaleDropEnd () {
if (state != 4) return;
// find center
let startcx = (startx + start2x) / 2;
let startcy = (starty + start2y) / 2;
let runcx = (runx + run2x) / 2;
let runcy = (runy + run2y) / 2;
// scale
let startlen = Math.sqrt(
Math.pow(start2x - startx, 2) + Math.pow(start2y - starty, 2)
);
let runlen = Math.sqrt(
Math.pow(run2x - runx, 2) + Math.pow(run2y - runy, 2)
);
let runscale = round3(drops * runlen / startlen);
// translate
let movetox = round3(runcx - startcx + dropx);
let movetoy = round3(runcy - startcy + dropy);
movetox = runcx - (runcx - movetox) * runscale / drops;
movetoy = runcy - (runcy - movetoy) * runscale / drops;
// set drop value
setDropXY(movetox, movetoy);
setDropScale(runscale);
setDropTransform();
};
// scale drop
function scaleDrop () {
if (state != 4) return;
// find center
let startcx = (startx + start2x) / 2;
let startcy = (starty + start2y) / 2;
let runcx = (runx + run2x) / 2;
let runcy = (runy + run2y) / 2;
// scale
let startlen = Math.sqrt(
Math.pow(start2x - startx, 2) + Math.pow(start2y - starty, 2)
);
let runlen = Math.sqrt(
Math.pow(run2x - runx, 2) + Math.pow(run2y - runy, 2)
);
let runscale = round3(drops * runlen / startlen);
// translate
let movetox = round3(runcx - startcx + dropx);
let movetoy = round3(runcy - startcy + dropy);
movetox = runcx - (runcx - movetox) * runscale / drops;
movetoy = runcy - (runcy - movetoy) * runscale / drops;
setDropTransform(movetox, movetoy, runscale);
};
// setRotate
function setRotate () {
if (tilemoving.length && state == 3) {
createCircle(movex, movey, dotmax[moven], "transparent", "#fc7")
.classList.add("rotatecirlce");
let centerx = movex * drops + dropx;
let centery = movey * drops + dropy;
let dx = startx - centerx;
let dy = starty - centery;
startr = Math.atan2(dy, dx) / Math.PI * 180;
}
};
// cancel wait active tile
function cancelWaitActive () {
if (waitactive.length) {
waitactive[0].setAttribute("stroke", colordrop);
let waitscale = getWaitScale(moven);
let waitstrokewidth = getWaitStrokeWidth(waitscale, 1);
waitactive[0].setAttribute("stroke-width", waitstrokewidth);
waitactive[0].classList.remove("waitactive");
}
};
// cancel snap tile
function cancelSnap () {
if (tilesnapped.length) {
tilesnapped[0].setAttribute("stroke", colormove);
tilesnapped[0].classList.remove("tilesnapped");
waitactive[0].setAttribute("stroke", colormove);
}
};
// set snap tile
function setSnap () {
if (tilemoving.length) {
tilemoving[0].setAttribute("stroke", colorsnap);
tilemoving[0].classList.add("tilesnapped");
toggleWaitActive(moven);
waitactive[0].setAttribute("stroke", colorsnap);
setMoveTransform();
}
};
// drop snap Tile or cancel snap
function dropSnap () {
if (ifNotGaming()) return;
if (tilemoving.length && tilesnapped.length) {
// cancel snap
cancelSnap();
if (
state == 1 &&
!clickt.classList.contains("tilewaiting") &&
!clickt.nextElementSibling.classList.contains("tilewaiting")
) {
tilemoving[0].removeAttribute("stroke");
tilemoving[0].removeAttribute("stroke-width");
tilemoving[0].classList.add("tiledropped");
tilemoving[0].classList.remove("tilemoving");
// recordHistory
recordHistory();
}
}
};
// calculate dot x
function cDotX (x, y, r, tx) {
let rt = r / 180 * Math.PI;
return x * Math.cos(rt) - y * Math.sin(rt) + tx;
};
// calculate dot y
function cDotY (x, y, r, ty) {
let rt = r / 180 * Math.PI;
return x * Math.sin(rt) + y * Math.cos(rt) + ty;
};
// get mid By tilen, XY and Radian
function getMidByNXYRF (n, x, y, r, f) {
return midFlip(dotmid[n], f).map((xy) => {
let midx = round3(cDotX(xy[0], xy[1], r, x));
let midy = round3(cDotY(xy[0], xy[1], r, y));
return [midx, midy];
});
};
// getDots By tilen, XY and Radian
function getDotsByNXYRF (n, x, y, r, f) {
return midFlip(dotxy[n], f).map((xy) => {
let dotx = round3(cDotX(xy[0], xy[1], r, x));
let doty = round3(cDotY(xy[0], xy[1], r, y));
return [dotx, doty];
});
};
// isIntersect after snapping
function isIntersect (neardropped, tmovex, tmovey, tmover) {
// tilemoving dots
let movedotxy = getDotsByNXYRF(moven, tmovex, tmovey, tmover, movef);
let movedotmid = getMidByNXYRF(moven, tmovex, tmovey, tmover, movef);
for (let k = 0; k < neardropped.length; k++) {
let i = neardropped[k];
// find every dropped tile center
let ddotn = getDropTileNumber(tiledropped[i]);
let ddotf = getDropTileFlip(tiledropped[i]);
let dmids = midFlip(dotmid[ddotn], ddotf);
let dlens = lenFlip(dotlen[ddotn], ddotf);
let dslopes = slopeFlip(dotslope[ddotn], ddotf);
// dropped xy and dropped radian
let tiledroppedxy = getDropTileXY(tiledropped[i]);
let tiledroppedx = tiledroppedxy[0];
let tiledroppedy = tiledroppedxy[1];
let tiledroppedr = getDropTileRotate(tiledropped[i]) * ddotf;
// actually drop dotxy
let dropdotxy = getDotsByNXYRF(ddotn,
tiledroppedx, tiledroppedy, tiledroppedr, ddotf);
let dropdotmid = getMidByNXYRF(ddotn,
tiledroppedx, tiledroppedy, tiledroppedr, ddotf);
// tilemoving and dropped is dumplicate
if (
ddotn == moven && ddotf == movef && tmover == tiledroppedr &&
Math.pow(tmovex - tiledroppedx, 2)
+ Math.pow(tmovey - tiledroppedy, 2)
< snapradius
) {
return true;
}
// tilemoving dots is in dropped
for (let j = 0; j < movedotxy.length; j++) {
let mx = movedotxy[j][0];
let my = movedotxy[j][1];
let isA1InA2 = false;
for (let i = 0; i < dropdotxy.length; i++) {
if (
Math.pow(mx - dropdotxy[i][0], 2)
+ Math.pow(my - dropdotxy[i][1], 2)
< snapradius
) {
isA1InA2 = true;
break;
}
}
if (isA1InA2) {
continue;
}
if (isPointInsidePolygon(mx, my, dropdotxy)) {
return true;
}
}
// tilemoving dotmid is in dropped
for (let j = 0; j < movedotmid.length; j++) {
let mx = movedotmid[j][0];
let my = movedotmid[j][1];
let isA1InA2 = false;
for (let i = 0; i < dropdotmid.length; i++) {
if (
Math.pow(mx - dropdotmid[i][0], 2)
+ Math.pow(my - dropdotmid[i][1], 2)
< snapradius
) {
isA1InA2 = true;
break;
}
}
if (isA1InA2) {
continue;
}
if (isPointInsidePolygon(mx, my, dropdotxy)) {
return true;
}
}
// tiledropped dots is in tilemoving
for (let j = 0; j < dropdotxy.length; j++) {
let dx = dropdotxy[j][0];
let dy = dropdotxy[j][1];
let isA1InA2 = false;
for (let i = 0; i < movedotxy.length; i++) {
if (Math.pow(dx - movedotxy[i][0], 2)
+ Math.pow(dy - movedotxy[i][1], 2)
< snapradius
) {
isA1InA2 = true;
break;
}
}
if (isA1InA2) {
continue;
}
if (isPointInsidePolygon(dx, dy, movedotxy)) {
return true;
}
}
// tiledropped dotmid is in tilemoving
for (let j = 0; j < dropdotmid.length; j++) {
let dx = dropdotmid[j][0];
let dy = dropdotmid[j][1];
let isA1InA2 = false;
for (let i = 0; i < movedotmid.length; i++) {
if (Math.pow(dx - movedotmid[i][0], 2)
+ Math.pow(dy - movedotmid[i][1], 2)
< snapradius
) {
isA1InA2 = true;
break;
}
}
if (isA1InA2) {
continue;
}
if (isPointInsidePolygon(dx, dy, movedotxy)) {
return true;
}
}
}
return false;
};
// snap to dot
function snapTileToDot (neardropped) {
// dropped tile dotmid
for (let k = 0; k < neardropped.length; k++) {
let i = neardropped[k];
// find every dropped tile center
let ddotn = getDropTileNumber(tiledropped[i]);
let ddotf = getDropTileFlip(tiledropped[i]);
let ddotxy = midFlip(dotxy[ddotn], ddotf);
// dropped xy and dropped radian
let tiledroppedxy = getDropTileXY(tiledropped[i]);
let tiledroppedx = parseFloat(tiledroppedxy[0]);
let tiledroppedy = parseFloat(tiledroppedxy[1]);
let tiledroppedr = getDropTileRotate(tiledropped[i]) * ddotf;
for (let j = 0; j < ddotxy.length; j++) {
let ddotx = ddotxy[j][0];
let ddoty = ddotxy[j][1];
let drx = cDotX(ddotx, ddoty, tiledroppedr, tiledroppedx);
let dry = cDotY(ddotx, ddoty, tiledroppedr, tiledroppedy);
// this moving tile dotmid
let dotxys = midFlip(dotxy[moven], movef);
for (let i = 0; i < dotxys.length; i++) {
let dotx = dotxys[i][0];
let doty = dotxys[i][1];
let rx = cDotX(dotx, doty, mover * movef, movex);
let ry = cDotY(dotx, doty, mover * movef, movey);
// calculate distance
let dotsdx = Math.pow(drx - rx, 2);
let dotsdy = Math.pow(dry - ry, 2);
if (Math.sqrt(dotsdx + dotsdy) > snapdotradius) {
continue;
}
// snap if not intersect
let tmovex = round3(movex + drx - rx);
let tmovey = round3(movey + dry - ry);
if (isIntersect(neardropped,
tmovex, tmovey, mover * movef)) {
continue;
}
setMoveXY(tmovex, tmovey);
setSnap();
break;
}
if (tilesnapped.length) {
break;
}
}
if (tilesnapped.length) {
break;
}
}
};
// slopeFlip
function slopeFlip (slope, flip) {
let newslope = slope.map((x) => {
return x * flip;
});
if (-1 == flip) {
newslope.reverse();
}
return newslope;
};
// lenFlip
function lenFlip (len, flip) {
let newlen = len.slice();
if (-1 == flip) {
newlen.reverse();
}
return newlen;
};
// midFlip
function midFlip (mid, flip) {
let newmid = mid.map((x) => {
return [x[0] * flip, x[1]];
});
if (-1 == flip) {
newmid.reverse();
}
return newmid;
};
// move and rotate snap tile
function snapTileToSide (neardropped) {
// dropped tile dotmid
for (let k = 0; k < neardropped.length; k++) {
let i = neardropped[k];
// find every dropped tile center
let ddotn = getDropTileNumber(tiledropped[i]);
let ddotf = getDropTileFlip(tiledropped[i]);
let dmids = midFlip(dotmid[ddotn], ddotf);
let dlens = lenFlip(dotlen[ddotn], ddotf);
let dslopes = slopeFlip(dotslope[ddotn], ddotf);
// dropped xy and dropped radian
let tiledroppedxy = getDropTileXY(tiledropped[i]);
let tiledroppedx = parseFloat(tiledroppedxy[0]);
let tiledroppedy = parseFloat(tiledroppedxy[1]);
let tiledroppedr = getDropTileRotate(tiledropped[i]) * ddotf;
for (let j = 0; j < dmids.length; j++) {
let dmidx = dmids[j][0];
let dmidy = dmids[j][1];
let drx = cDotX(dmidx, dmidy, tiledroppedr, tiledroppedx);
let dry = cDotY(dmidx, dmidy, tiledroppedr, tiledroppedy);
// this moving tile dotmid
let mids = midFlip(dotmid[moven], movef);
let lens = lenFlip(dotlen[moven], movef);
let slopes = slopeFlip(dotslope[moven], movef);
for (let i = 0; i < mids.length; i++) {
let midx = mids[i][0];
let midy = mids[i][1];
let rx = cDotX(midx, midy, mover * movef, movex);
let ry = cDotY(midx, midy, mover * movef, movey);
// calculate distance
let dotsdx = Math.pow(drx - rx, 2);
let dotsdy = Math.pow(dry - ry, 2);
let dotsd = Math.sqrt(dotsdx + dotsdy);
if (dlens[j] != lens[i] || dotsd > lens[i] * snapratio) {
continue;
}
// calculate ratio
let snapr = 180;
snapr += dslopes[j] + tiledroppedr;
snapr -= slopes[i] + mover * movef;
snapr = degree180(snapr);
if (snapr > snapradian || snapr < -snapradian) {
continue;
}
// snap if not intersect
let tmover = mover + snapr * movef;
let snapx = cDotX(midx, midy, tmover * movef, movex);
let snapy = cDotY(midx, midy, tmover * movef, movey);
let tmovex = round3(movex + drx - snapx);
let tmovey = round3(movey + dry - snapy);
if (isIntersect(neardropped,
tmovex, tmovey, tmover * movef)) {
continue;
}
setMoveXY(tmovex, tmovey);
setMoveRotate(tmover);
setSnap();
break;
}
if (tilesnapped.length) {
break;
}
}
if (tilesnapped.length) {
break;
}
}
};
// snapTile
function snapTile () {
if (ifNotGaming()) return;
if (!tiledropped.length && mode == 0) {
setSnap();
} else if (state == 2 || state == 3) {
// collect near dropped tile
let neardropped = [];
for (let i = 0; i < tiledropped.length; i++) {
// find every dropped tile center
let ddotn = getDropTileNumber(tiledropped[i]);
let ddotf = getDropTileFlip(tiledropped[i]);
// dropped xy and dropped radian
let tiledroppedxy = getDropTileXY(tiledropped[i]);
let tiledroppedx = tiledroppedxy[0];
let tiledroppedy = tiledroppedxy[1];
let tiledroppedr = getDropTileRotate(tiledropped[i]) * ddotf;
// search nearby
if (Math.pow(movex - tiledroppedx, 2)
+ Math.pow(movey - tiledroppedy, 2)
< Math.pow(dotmax[moven] + dotaver[ddotn], 2)
) {
neardropped.push(i);
}
}
// snap to dot
if (getSnapTo()) {
snapTileToDot(neardropped);
}
// snap to side
else {
snapTileToSide(neardropped);
}
}
};
// if not gaming state
function ifNotGaming () {
if (state == -1) return true;
return false;
};
// set state to 0
function setEndValue (e) {
if (ifNotGaming()) return;
endtime = Date.now();
if (state == 4) {
let ejtile_rect = etmain.getBoundingClientRect();
let rectx = ejtile_rect.x + window.scrollX;
let recty = ejtile_rect.y + window.scrollY;
let rtx = e.touches[0].pageX - rectx;
let rty = e.touches[0].pageY - recty;
startx = Math.round(rtx);
starty = Math.round(rty);
state = 1;
starttime -= clicktime;
} else {
state = 0;
}
// remove wait2move if mode 1
if (mode) {
let wait2move = document.getElementsByClassName("wait2move");
while (wait2move.length) {
wait2move[0].classList.remove("wait2move");
}
}
};
// moveDropEnd
function moveDropEnd () {
if (state != 1) return;
let movetox = round3(endx - startx + dropx);
let movetoy = round3(endy - starty + dropy);
setDropXY(movetox, movetoy);
setDropTransform();
};
// moveDrop
function moveDrop () {
if (state != 1) return;
let movetox = round3(runx - startx + dropx);
let movetoy = round3(runy - starty + dropy);
setDropTransform(movetox, movetoy);
};
// clickEventUP
function clickEventUP () {
if (ifNotGaming()) return;
if (Date.now() - starttime < clicktime &&
Math.pow(endx - startx, 2) + Math.pow(endy - starty, 2) < clickradius
) {
// moving mode
if (mode) {
if (clickt == tilemoving[0]) {
if (clickt.classList.contains("wait2move")) {
clickt.classList.remove("wait2move");
} else {
flipTile();
}
}
return;
}
// flip tile
if (!doubleclick && (clickm == 1 || clickm == 2) &&
clickt == tilemoving[0]
) {
flipTile();
}
// remove dropped tile
if (!doubleclick && clickm == 1 &&
clickt.classList.contains("tiledropped")
) {
clickt.remove();
// recordHistory
recordHistory();
}
// move tile here
if (
!doubleclick && clickm == 1 && clickt == etmain &&
state != 3 && state != 4
) {
setMoveXY((endx - dropx) / drops, (endy - dropy) / drops);
setMoveTransform();
state = 2;
}
// next tile
if (doubleclick && (lastclickm == 1 || lastclickm == 2) &&
lastclickt == tilemoving[0] && clickt == tilemoving[0]
) {
flipTile();
moven += 1;
if (moven == etdefs.children.length) {
moven = 0;
}
setMoveNumber();
setMoveRotate(getTileWaitRotate());
setMoveFlip(getTileWaitFlip());
setMoveFill();
setMoveTransform();
}
// remove moving tile
if (doubleclick && clickm == 1 &&
lastclickm == 1 && lastclickt == etmain
) {
if (tilemoving.length) {
tilemoving[0].remove();
}
}
// remove dropped tile
if (clickm == 0 && clickt.classList.contains("tiledropped")) {
clickt.remove();
// recordHistory
recordHistory();
}
}
};
// clickEventDown
function clickEventDown () {
if (ifNotGaming()) return;
if (mode) return;
if (Date.now() - endtime < clicktime &&
Math.pow(endx - startx, 2) + Math.pow(endy - starty, 2) < clickradius
) {
// flip moving tile
if (
doubleclick && state == 2 &&
(lastclickm == 0 || lastclickm == 2) &&
lastclickt == etmain
) {
flipTile();
}
// undo Rmove Drop with double click
if (doubleclick && (lastclickm == 1 || lastclickm == 0) &&
lastclickt.classList.contains("tiledropped")
) {
etdrop.appendChild(lastclickt);
if (tilemoving.length) {
etdrop.appendChild(tilemoving[0]);
}
// recordHistory
recordHistory();
}
}
};
// isPointInsidePolygon
function isPointInsidePolygon(x, y, vertices) {
let inside = false;
for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {
const xi = vertices[i][0], yi = vertices[i][1];
const xj = vertices[j][0], yj = vertices[j][1];
const intersect = ((yi > y) !== (yj > y)) &&
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
};
// set move fill
function setMoveFill (fill = getTileFill()) {
if (tilemoving.length) {
tilemoving[0].setAttribute('fill', fill);
tilewaiting[moven].setAttribute('fill', fill);
}
};
// get tile fill
function getTileFill (n = moven) {
let movet = etdefs.children[n];
let fill = "blue";
if (movef == 1) {
fill = movet.getAttribute("frontfill");
} else {
fill = movet.getAttribute("backfill");
}
return fill;
};
// flip tile
function flipTile () {
movef *= -1;
mover *= -1;
setMoveFill();
setMoveTransform();
};
// active waiting tile
function moveMode () {
if (ifNotGaming()) return;
if (mode) {
if (clickt.classList.contains("tiledropped")) {
// remove rotatecirlce
while (rotatecirlce.length) {
rotatecirlce[0].remove();
}
// remove tilemoving
if (tilemoving.length) {
tilemoving[0].removeAttribute("stroke");
tilemoving[0].removeAttribute("stroke-width");
tilemoving[0].classList.add("tiledropped");
tilemoving[0].classList.remove("tilemoving");
}
clickt.setAttribute("stroke", colormove);
clickt.setAttribute("stroke-width", strokewidthmove);
clickt.classList.remove("tiledropped");
clickt.classList.add("tilemoving", "wait2move");
while (clickt != etdrop.lastChild) {
etdrop.insertBefore(etdrop.lastChild, clickt);
}
setMoveNumber(getMoveNumber());
setMoveXY(getMoveXY()[0], getMoveXY()[1]);
setMoveRotate(getMoveRotate());
setState();
}
// drop moving
else if (
state != 2 && state != 3 &&
tilemoving.length && clickt != tilemoving[0] &&
!clickt.classList.contains("tilewaiting") &&
(null == clickt.nextElementSibling ||
!clickt.nextElementSibling.classList.contains("tilewaiting"))
) {
if (tilemoving.length) {
tilemoving[0].removeAttribute("stroke");
tilemoving[0].removeAttribute("stroke-width");
tilemoving[0].classList.add("tiledropped");
tilemoving[0].classList.remove("tilemoving");
}
cancelSnap();
cancelWaitActive();
}
}
};
// mouse END
// init START
// get defs children's dots
function getDots (path) {
let pathd = path.getAttribute("d");
pathd = pathd.replace(/^M /, "").replace(/ Z.*$/, "");
let pathdarr = pathd.split(" L ");
let pathdarrmap = pathdarr.map((x) => {
let xsplit = x.split(",");
return [parseFloat(xsplit[0]), parseFloat(xsplit[1])];
});
return pathdarrmap;
};
// calculateDots
function calculateDots () {
dotmax = [], dotaver = [];
dotxy = [], dotmid = [], dotlen = [], dotslope = [];
for (let i = 0; i < etdefs.children.length; i++) {
let dots = getDots(etdefs.children[i].firstElementChild);
// dot xy
dotxy.push(dots);
let thisdotmax = 0, thisdotaver = 0, thisdotsum = 0;
let thisdotmid = [], thisdotlen = [], thisdotslope = [];
for (let i = 0; i < dots.length; i++) {
// dotmax, dotaver
let thisdot = dots[i];
let thisdl = Math.pow(thisdot[0], 2) + Math.pow(thisdot[1], 2);
thisdl = round3(Math.sqrt(thisdl));
thisdotsum += thisdl;
if (thisdl > thisdotmax) {
thisdotmax = thisdl;
}
// dotmid
let crtdot, nxtdot;
if (i < dots.length - 1) {
crtdot = dots[i];
nxtdot = dots[i + 1];
} else {
crtdot = dots[dots.length - 1];
nxtdot = dots[0];
}
let midx = round3((crtdot[0] + nxtdot[0]) / 2);
let midy = round3((crtdot[1] + nxtdot[1]) / 2);
thisdotmid.push([midx, midy]);
// dotlen
let lenx = (crtdot[0] - nxtdot[0]) * (crtdot[0] - nxtdot[0]);
let leny = (crtdot[1] - nxtdot[1]) * (crtdot[1] - nxtdot[1]);
let len = Math.round(Math.sqrt(lenx + leny));
thisdotlen.push(len);
// dotslope
let slopex = crtdot[0] - nxtdot[0];
let slopey = crtdot[1] - nxtdot[1];
let slopev = Math.atan2(slopey, slopex) / Math.PI * 180;
if ("int" == getSlopeType()) {
slopev = Math.round(slopev);
}
thisdotslope.push(slopev);
}
// dotmax
dotmax.push(thisdotmax + rotatepadding);
// dotaver
thisdotaver = round3(thisdotsum / dots.length);
dotaver.push(thisdotaver);
// dotmid
dotmid.push(thisdotmid);
// dotlen
dotlen.push(thisdotlen);
// dotslope
dotslope.push(thisdotslope);
}
};
// createUploadForm
function createUploadForm () {
if (null == document.getElementById("uploadform")) {
let ejform = document.createElement("form");
ejform.setAttribute("id", "uploadform");
let ejuploadinput = document.createElement("input");
ejuploadinput.setAttribute("type", "file");
ejuploadinput.classList.add("ejuploadinput");
ejform.appendChild(ejuploadinput);
ejform.style.display = "none";
let ejbody = document.getElementsByTagName("body")[0];
ejbody.appendChild(ejform);
ejuploadinput.onchange = function (e) {
let reader = new FileReader();
reader.readAsText(e.target.files[0]);
reader.onload = function(){
etmain.outerHTML = this.result;
etinit();
// recordHistory
recordHistory();
};
};
}
};
// mode init
function modeInit () {
mode = parseInt(etdefs.getAttribute("mode"));
if (!mode) return;
if (tiledropped.length) return;
for (let i = 0; i < etdefs.children.length; i++) {
let thisdotmax = dotmax[i];
let rotatestart = getRotateStart();
createTile(
i,
thisdotmax + rotatepadding + 80,
thisdotmax + rotatepadding,
1, rotatestart, getTileFill(i), colordrop, strokewidthdrop
).classList.add("tiledropped");
}
};
// toggle Wait Active
function toggleWaitActive (n) {
for (let i = 0; i < tilewaiting.length; i++) {
let waitscale = getWaitScale(i);
if (i == n) {
tilewaiting[i].setAttribute("stroke", colormove);
tilewaiting[i].classList.add("waitactive");
tilewaiting[i].setAttribute("stroke-width",
getWaitStrokeWidth(waitscale, 2)
);
} else {
tilewaiting[i].setAttribute("stroke", colordrop);
tilewaiting[i].classList.remove("waitactive");
tilewaiting[i].setAttribute("stroke-width",
getWaitStrokeWidth(waitscale, 1)
);
}
}
};
// add tile waiting
function addTileWaiting () {
for (let i = 0; i < dotmax.length; i++) {
// outer and rect
let waitouter = document.createElementNS(
'http://www.w3.org/2000/svg', 'g');
let waitbg = document.createElementNS(
'http://www.w3.org/2000/svg', 'rect');
waitbg.setAttribute("x", "0");
waitbg.setAttribute("y", i * 40);
waitbg.setAttribute("width", "40");
waitbg.setAttribute("height", "40");
waitbg.setAttribute("fill", "white");
waitouter.appendChild(waitbg);
// add waitile
let waitscale = getWaitScale(i);
let waitstrokewidth = getWaitStrokeWidth(waitscale, 1);
let newtilewaiting = createTile(i, 20, 20 + 40 * i, 1, 0,
getTileFill(i), colormove, waitstrokewidth, waitouter);
newtilewaiting.classList.add("tilewaiting");
let waittransform = newtilewaiting.getAttribute("transform")
.replace(/(.*scale\().*?(\).*)/, "$1" + waitscale + "$2");
newtilewaiting.setAttribute("transform", waittransform);
if (mode == 0) {
if (i == moven) {
newtilewaiting.setAttribute("stroke", colormove);
newtilewaiting.classList.add("waitactive");
newtilewaiting.setAttribute("stroke-width",
getWaitStrokeWidth(waitscale, 2)
);
} else {
newtilewaiting.setAttribute("stroke", colordrop);
newtilewaiting.setAttribute("stroke-width",
getWaitStrokeWidth(waitscale, 1)
);
}
}
waitouter.onclick = ejtileWaitClick;
waitouter.ontouchstart = function (e) {
e.preventDefault();
ejtileWaitClick(e);
};
etwait.appendChild(waitouter);
}
};
// create etwait
function createWait () {
etwait = etmain.querySelector(".etwait");
if (etwait) {
etwait.removeAttribute("display");
} else {
etwait = document.createElementNS(
'http://www.w3.org/2000/svg', 'g');
etwait.classList.add("etwait");
etmain.appendChild(etwait);
addTileWaiting();
}
};
// create etdrop
function createDrop () {
etdrop = etmain.querySelector(".etdrop");
if (null == etdrop) {
etdrop = document.createElementNS(
'http://www.w3.org/2000/svg', 'g');
etdrop.classList.add("etdrop");
etdrop.setAttribute("stroke", colordrop);
etdrop.setAttribute("stroke-width", strokewidthdrop);
etmain.appendChild(etdrop);
}
};
// init ejtile
function etinit () {
// handle element
etmain = document.getElementById("etmain");
etdefs = etmain.getElementsByTagName("defs")[0];
createDrop();
// mouse event
etmain.onmousedown = ejtileMouseDown;
etmain.onmousemove = ejtileMouseMove;
etmain.onmouseup = ejtileMouseUp;
etmain.onmouseleave = ejtileMouseUp;
etmain.onwheel = ejtileMouseWheel;
etmain.ontouchstart = function (e) {
e.preventDefault();
ejtileMouseDown(e);
};
etmain.ontouchmove = function (e) {
e.preventDefault();
ejtileMouseMove(e);
};
etmain.ontouchend = function (e) {
e.preventDefault();
ejtileMouseUp(e);
};
// calculate radius for dotmax and dotaver
calculateDots();
// get and set
setDropXY(getDropXY()[0], getDropXY()[1]);
setDropScale(getDropScale());
setMoveXY(getMoveXY()[0], getMoveXY()[1]);
setMoveRotate(getMoveRotate());
setMoveFlip(getMoveFlip());
setMoveNumber(getMoveNumber());
setRotateSnap(getRotateSnap());
setRotateStart(getRotateStart());
setRotateStep(getRotateStep());
// createUploadForm
createUploadForm();
// ejtile mode
modeInit();
// createWait and add tile waiting
createWait();
};
// etmain Mouse Down
function ejtileMouseDown (e) {
setStartXY(e);
setStartValue(e);
moveMode();
setRotate();
dropSnap();
addNewTile();
clickEventDown()
};
// etmain Mouse Move
function ejtileMouseMove (e) {
setRunXY(e);
moveDrop();
moveTile();
rotateTile();
scaleDrop();
};
// etmain Mouse Up
function ejtileMouseUp (e) {
setEndXY(e);
moveDropEnd();
moveTileEnd();
rotateTileEnd();
scaleDropEnd();
clickEventUP();
snapTile();
setEndValue(e);
};
// init END
</script></p>
</body>
</html>