做了一個svg 三角形畫板

分享和讨论Javascript相关的话题
头像
ejsoon
圈圈精英
圈圈精英
帖子: 2254
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 99 次
被赞次数: 99 次
联系:

Re: 做了一個svg 三角形畫板

帖子 ejsoon »

不鏽鋼隱身機.jpg
不鏽鋼隱身機.jpg (9.66 KiB) 查看 1155 次
https://ejsoon.win/
天蒼人頡:發掘好玩事物
头像
ejsoon
圈圈精英
圈圈精英
帖子: 2254
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 99 次
被赞次数: 99 次
联系:

源碼分享

帖子 ejsoon »

代码: 全选

<p>因為我手機上的simplector不能方便的畫正三角形svg,因此我製作了此工具。▼◀</p>
<form id="ejmondouter">
<div id="svgouter">
<div id="svginner"></div>
<div><svg id="ejmond" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" width="480" height="480" viewbox="0 0 480 480"></svg></div>
</div>
<div></div>
<div class="ejmondbtn"><label class="ejmondlabel"> <input type="radio" name="pointtype" value="1" checked="checked" /> △ </label> <label class="ejmondlabel"> <input type="radio" name="pointtype" value="0" /> ▷ </label> <label class="ejmondlabel" style="float: right;"> <input type="checkbox" name="net" value="1" /> net </label></div>
<div></div>
<div class="ejmondbtn"><button type="button" onclick="undo()">undo</button> <button type="button" onclick="finish()">finish</button> <button type="button" onclick="downloadsvg()" style="float: right;">download</button></div>
</form>
<p><style>
#ejmondouter {text-align: center;}
.ejmondbtn {display: inline-block; width: 100%; max-width: 480px; text-align: left;}
.ejmondlabel {display: inline-block; border: 1px solid #444; border-radius: 7px; padding: 7px 24px;}
#ejmond {width: 100%; height: 100%; position: absolute; top: 0; left: 0;}
#svgouter {display: inline-block; position: relative; max-width: 100%;}
#svginner {width: 480px; max-width: 100%; padding-top: 100%; background-color: #fff;}
.hide {display: none;}
</style> <script>
var ejform = document.getElementById("ejmondouter");
var ejmond = document.getElementById("ejmond");
var paths = ejmond.getElementsByClassName("ejmond_path");
var paths_continue = ejmond.getElementsByClassName("continue");
var ejpoint_g, netpathmask, netpath;
addManyDots();
addLine();
// make dot
ejform.onchange = function (e) {
	if (e.target.name == "pointtype") {
		modifyManyDots();
		modifyLine();
	}
	else if (e.target.name == "net") {
		if (ejform.elements.net.checked) {
			addMask();
		} else {
			removeMask();
		}
	}
};
function addManyDots () {
	ejpoint_g = document.createElementNS('http://www.w3.org/2000/svg',
		'g');
	ejpoint_g.classList.add("point_g");
	ejmond.appendChild(ejpoint_g);
	modifyManyDots();
}
function modifyManyDots () {
	let direction = ejform.elements.pointtype.value;
	let sqrt3 = Math.sqrt(3);
	let dots = ejmond.getElementsByClassName("ejmond_point");
	let minidots = ejmond.getElementsByClassName("ejmond_minipoint");
	// clear dots
	while (dots.length) {
		dots[0].remove();
	}
	while (minidots.length) {
		minidots[0].remove();
	}
	if ("1" == direction) {
		for (let j = -3; j <= 3; j++) {
			for (let i = 0; i <= 12; i++) {
				addDot(i * 36 + 24, 240 + sqrt3 * 36 * j);
				if (j < 3 && i < 12) {
					addDot(i * 36 + 42, 240 + sqrt3 * (36 * j + 18));
				}
			}
		}
	} else {
		for (let j = -3; j <= 3; j++) {
			for (let i = 0; i <= 12; i++) {
				addDot(240 + sqrt3 * 36 * j, i * 36 + 24);
				if (j < 3 && i < 12) {
					addDot(240 + sqrt3 * (36 * j + 18), i * 36 + 42);
				}
			}
		}
	}
}
function addDot (cx, cy) {
	// cdot
	let cdot = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
	cdot.classList.add("ejmond_point");
	cdot.setAttribute("cx", cx);
	cdot.setAttribute("cy", cy);
	cdot.setAttribute("r", "12");
	cdot.setAttribute("fill", "#ffffff");
	ejpoint_g.appendChild(cdot);
	// minidot
	let minidot = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
	minidot.classList.add("ejmond_minipoint");
	minidot.setAttribute("cx", cx);
	minidot.setAttribute("cy", cy);
	minidot.setAttribute("r", "1");
	minidot.setAttribute("fill", "#444");
	ejpoint_g.appendChild(minidot);
}
// mousedown
var state = 0;
ejmond.onmousedown = ejmondDown;
ejmond.ontouchstart = function (e) {
	e.preventDefault();
	ejmondDown(e);
}
function ejmondDown(e) {
	if (state == 0) {
		if (e.target.classList.contains("ejmond_point") || 
			e.target.classList.contains("ejmond_minipoint")) {
			state = 4;
			addPath(e);
		}
	} else {
		if (e.target.classList.contains("ejmond_point") || 
			e.target.classList.contains("ejmond_minipoint")) {
			if (paths_continue.length ||
				!e.target.classList.contains("start")) {
				state = 2;
				continuePath(e);
			}
		}
	}
	pTypeDisable();
};
ejmond.onmouseup = ejmondUp;
ejmond.ontouchend = function (e) {
	e.preventDefault();
	ejmondUp(e);
}
function ejmondUp (e) {
	if (state == 2) {
		state = 1;
	}
	else if (state == 4) {
		state = 3;
	}
};
ejmond.onmousemove = ejmondMove;
function ejmondMove(e) {
	if (state == 2 || state == 4) {
		if (e.target.classList.contains("ejmond_point") || 
			e.target.classList.contains("ejmond_minipoint")) {
			if (state == 2 || !e.target.classList.contains("start")) {
				state = 2;
				continuePath(e);
			}
		}
	}
};
function addPath (e) {
	// addPath
	var ejpath = document.createElementNS('http://www.w3.org/2000/svg',
		'path');
	ejpath.classList.add("ejmond_path");
	ejpath.setAttribute("fill", "none");
	ejpath.setAttribute("stroke-width", "4");
	ejpath.setAttribute("stroke-linecap", "round");
	ejpath.setAttribute("stroke-linejoin", "round");
	ejpath.setAttribute("stroke", "#4c4");
	let cx = Number.parseFloat(e.target.getAttribute("cx"));
	let cy = Number.parseFloat(e.target.getAttribute("cy"));
	ejpath.setAttribute("d", "M " + Math.round(cx) + " " + Math.round(cy)) ;
	ejmond.appendChild(ejpath);
	// add start
	var startdot = document.createElementNS('http://www.w3.org/2000/svg',
		'circle');
	startdot.classList.add("ejmond_point", "start");
	startdot.setAttribute("cx", cx);
	startdot.setAttribute("cy", cy);
	startdot.setAttribute("r", "12");
	startdot.setAttribute("fill", "#d9a");
	ejmond.appendChild(startdot);
}
function continuePath (e) {
	if (e.target.classList.contains("start")) {
		finish(true);
	} else if (!e.target.classList.contains("continue")) {
		e.target.classList.add("continue");
		e.target.classList.add("continue" + paths_continue.length);
		let pathd = paths[paths.length - 1].getAttribute("d");
		let pathcx = Number.parseFloat(e.target.getAttribute("cx"));
		let pathcy = Number.parseFloat(e.target.getAttribute("cy"));
		pathd += " L " + Math.round(pathcx) + " " + Math.round(pathcy);
		paths[paths.length - 1].setAttribute("d", pathd);
	}
}
// end mousemove
// download
function downloadsvg() {
	let ejmond_clone = ejmond.cloneNode(true);
	ejmond_clone.getElementsByClassName("point_g")[0].remove();
	// remove mask
	if (!ejform.elements.net.checked) {
		ejmond_clone.querySelector(".netpath").remove();
		ejmond_clone.querySelector(".netpathmask").remove();
	}
	// download
	let a = document.createElement('a'); 
	a.style.display = "none";
	let data = ejmond_clone.outerHTML;
	let file = new Blob([data], {type: "data:image/svg"});
	a.href = URL.createObjectURL(file);
	a.download = "ejpath.svg";
	document.body.appendChild(a);
	a.click();
	document.body.removeChild(a);
}
// undo
function undo() {
	if (state == 3) {
		ejmond.querySelector(".start").remove();
		paths[paths.length - 1].remove();
		state = 0;
	}
	else if (state == 1) {
		let last_continue = ejmond.querySelector(".continue"
			+ paths_continue.length);
		last_continue.classList.remove("continue" + paths_continue.length);
		last_continue.classList.remove("continue");
		let pathd = paths[paths.length - 1].getAttribute("d");
		let last_L = pathd.lastIndexOf("L");
		pathd = pathd.substring(0, last_L);
		paths[paths.length - 1].setAttribute("d", pathd);
		if (!paths_continue.length) {
			state = 3;
		}
	}
	else if (state == 0) {
		if (paths.length) {
			paths[paths.length - 1].remove();
		}
	}
	pTypeDisable();
	if (ejform.elements.net.checked) {
		addMask();
	}
}
// finish
function finish(funfn = false) {
	if (state == 1 || funfn) {
		ejmond.querySelector(".start").remove();
		for (let i = 1; i <= paths_continue.length; i++) {
			ejmond.querySelector(".continue" + i)
				.classList.remove("continue" + i);
		}
		while (paths_continue.length) {
			paths_continue[0].classList.remove("continue");
		}
		if (funfn) {
			let pathd = paths[paths.length - 1].getAttribute("d");
			pathd += " Z";
			paths[paths.length - 1].setAttribute("d", pathd);
		}
		paths[paths.length - 1].setAttribute("stroke", "#444");
		state = 0;
	}
	if (ejform.elements.net.checked) {
		addMask();
	}
}
// disable input radio
function pTypeDisable () {
	let ejradio = ejform.querySelectorAll("input[name=pointtype]");
	for (let x = 0; x < ejradio.length; x++) {
		if (state == 0 && !paths.length) {
			ejradio[x].removeAttribute("disabled");
		} else {
			ejradio[x].setAttribute("disabled", true);
		}
	}
}
// add line
function addLine () {
	netpathmask = document.createElementNS('http://www.w3.org/2000/svg',
		'mask');
	netpathmask.setAttribute("id", "netmask");
	netpathmask.classList.add("netpathmask");
	ejmond.appendChild(netpathmask);
	netpath = document.createElementNS('http://www.w3.org/2000/svg',
		'path');
	netpath.classList.add("netpath");
	netpath.setAttribute("mask", "url(#netmask)");
	netpath.setAttribute("fill", "none");
	netpath.setAttribute("stroke-linecap", "round");
	netpath.setAttribute("stroke-linejoin", "round");
	netpath.setAttribute("stroke-dasharray", "1, 5");
	netpath.setAttribute("stroke-width", "1");
	netpath.setAttribute("stroke", "#777");
	ejmond.appendChild(netpath);
	modifyLine();
}
// modify line
function modifyLine () {
	let path_d = "";
	let sqrt3 = Math.sqrt(3);
	let direction = ejform.elements.pointtype.value;
	if ("1" == direction) {
		for (let i = -5; i < 12; i++) {
			path_d += "M " + (i * 36 + 24) + " "
				+ Math.round(240 + sqrt3 * 36 * (-3));
			path_d += "l " + (6 * 36) + " " + (sqrt3 * 36 * 6);
		}
		for (let i = 1; i < 18; i++) {
			path_d += "M " + (i * 36 + 24) + " "
				+ Math.round(240 + sqrt3 * 36 * (-3));
			path_d += "l " + (-6 * 36) + " " + (sqrt3 * 36 * 6);
		}
		for (let i = -6; i <= 6; i++) {
			path_d += "M " + 24 + " "
				+ Math.round(240 + sqrt3 * 18 * i);
			path_d += "h " + (12 * 36);
		}
	} else {
		for (let i = -5; i < 12; i++) {
			path_d += "M " + Math.round(240 + sqrt3 * 36 * (-3)) + " "
				+ (i * 36 + 24);
			path_d += "l " + (sqrt3 * 36 * 6) + " " + (6 * 36);
		}
		for (let i = 1; i < 18; i++) {
			path_d += "M " + Math.round(240 + sqrt3 * 36 * (-3)) + " "
				+ (i * 36 + 24);
			path_d += "l " + (sqrt3 * 36 * 6) + " " + (-6 * 36);
		}
		for (let i = -6; i <= 6; i++) {
			path_d += "M " + Math.round(240 + sqrt3 * 18 * i) + " "
				+ 24;
			path_d += "v " + (12 * 36);
		}
	}
	netpath.setAttribute("d", path_d);
}
// add mask
function addMask () {
	netpathmask.innerHTML = "";
	for (let i = 0; i < paths.length; i++) {
		if (i < paths.length - 1 || state == 0) {
			let pathclone = paths[i].cloneNode(true);
			pathclone.classList.remove("ejmond_path");
			pathclone.setAttribute("fill", "#ffffff");
			pathclone.setAttribute("stroke", "none");
			netpathmask.appendChild(pathclone);
		}
	}
	netpath.classList.remove("hide");
}
// remove mask
function removeMask () {
	netpath.classList.add("hide");
}
</script></p>
https://ejsoon.win/
天蒼人頡:發掘好玩事物
回复

在线用户

正浏览此版面之用户: 没有注册用户 和 6 访客