繁体   English   中英

HTML5 Canvas Scallop Shape

[英]HTML5 Canvas Scallop Shape

我真的需要帮助如何使用Canvas创建扇贝形状我尝试在云样本周围玩耍但是我很难创建我想要的东西。

我只是想知道矩形和圆形扇贝形状的代码。

这是我想要的形象。 扇贝设计

它的设计不一定完全相同,但它看起来像这样。

非常感谢你!

您可以使用虚线划线画出这样的形状,就像这样(有点棘手)。

JavaScript的:

const canvas = document.querySelector("#canvas");
canvas.width = canvas.height = 300;
const ctx = canvas.getContext("2d");
const rect = [50, 50, 200, 200];
//draw dotted line dash.
ctx.lineCap = "round";
ctx.setLineDash([0, 40]);
ctx.lineDashOffset = 20;
ctx.lineWidth = 42;
ctx.strokeStyle = "purple";
ctx.strokeRect(...rect);
//remove disuse range.
ctx.globalCompositeOperation = "destination-out";
ctx.lineWidth = 38;
ctx.strokeRect(...rect);
ctx.fillRect(...rect);

演示:
http://jsdo.it/defghi1977/iFR7

从较旧的答案,但问题非常模糊,并有很多额外的包袱。 这是答案的片段。 它有一些额外的代码,可能有帮助但不直接相关。

功能显示(大约一半)完成大部分工作,将弧添加到对象框。

请参阅运行演示以获取指导

 const pointSize = 4; const pointCol = "#4AF"; var arcDepth = -0.5; // depth of arc as a factor of line seg length // Note to have arc go the other (positive) way you have // to change the ctx.arc draw call by adding anticlockwise flag // see drawArc for more const arcCol = "#F92"; const arcWidth = 8; // Find a circle that fits 3 points. function fitCircleTo3P(p1x, p1y, p2x, p2y, p3x, p3y, arc) { var vx, vy, c, c1, u; c = (p2x - p1x) / (p1y - p2y); // slope of vector from vec 1 to vec 2 c1 = (p3x - p2x) / (p2y - p3y); // slope of vector from vec 2 to vec 3 // This will not happen in this example if (c === c1) { // if slope is the same they must be on the same line return null; // points are in a line } // locate the center if (p1y === p2y) { // special case with p1 and p2 have same y vx = (p1x + p2x) / 2; vy = c1 * vx + (((p2y + p3y) / 2) - c1 * ((p2x + p3x) / 2)); } else if (p2y === p3y) { // special case with p2 and p3 have same y vx = (p2x + p3x) / 2; vy = c * vx + (((p1y + p2y) / 2) - c * ((p1x + p2x) / 2)); } else { vx = ((((p2y + p3y) / 2) - c1 * ((p2x + p3x) / 2)) - (u = ((p1y + p2y) / 2) - c * ((p1x + p2x) / 2))) / (c - c1); vy = c * vx + u; } arc.x = vx; arc.y = vy; vx = p1x - vx; vy = p1y - vy; arc.rad = Math.sqrt(vx * vx + vy * vy); return arc; } var points = []; var arcs = []; function addArc(p1, p2, depth) { var arc = { p1 : p1, p2 : p2, depth : depth, rad : null, // radius a1 : null, // angle from a2 : null, // angle to x : null, y : null, } arcs.push(arc); return arc; } function calcArc(arc, depth) { var p = points[arc.p1]; // get points var pp = points[arc.p2]; // change depth if needed depth = arc.depth = depth !== undefined ? depth : arc.depth; var vx = pp[0] - p[0]; // vector from p to pp var vy = pp[1] - p[1]; var cx = (pp[0] + p[0]) / 2; // center point var cy = (pp[1] + p[1]) / 2; // center point var len = Math.sqrt(vx * vx + vy * vy); // get length cx -= vy * depth; // find 3 point at 90 deg to line and dist depth cy += vx * depth; // To have depth as a fixed length uncomment 4 lines below and comment out 2 lines above. //var nx = vx / len; // normalise vector //var ny = vy / len; //cx -= ny * depth; // find 3 point at 90 deg to line and dist depth //cy += nx * depth; fitCircleTo3P(p[0], p[1], cx, cy, pp[0], pp[1], arc); // get the circle that fits arc.a1 = Math.atan2(p[1] - arc.y, p[0] - arc.x); // get angle from circle center to first point arc.a2 = Math.atan2(pp[1] - arc.y, pp[0] - arc.x); // get angle from circle center to second point } function addPoint(x, y) { points.push([x, y]); } function drawPoint(x, y, size, col) { ctx.fillStyle = col; ctx.beginPath(); ctx.arc(x, y, size, 0, Math.PI * 2); ctx.fill(); } function drawArcStart(width,col){ ctx.lineCap = "round"; ctx.strokeStyle = col; ctx.lineJoin = "round"; ctx.lineWidth = width; ctx.beginPath(); } function drawArc(arc){ ctx.arc(arc.x,arc.y,arc.rad,arc.a1,arc.a2); } function drawArcDone(){ ctx.closePath(); ctx.stroke(); } function findClosestPoint(x, y, dist) { var index = -1; for (var i = 0; i < points.length; i++) { var p = points[i]; var vx = x - p[0]; var vy = y - p[1]; var d = Math.sqrt(vx * vx + vy * vy); if (d < dist) { dist = d; index = i; } } return index; } var dragging = false; var drag = -1; var dragX, dragY; var recalcArcs = false; var box; //======================================================================== // New box code from here down // creates the box when canvas is ready var onResize = function(){ box = { x : canvas.width * (1/8), y : canvas.height * (1/8), w : canvas.width * (6/8), h : canvas.height * (6/8), recalculate : true, arcCount : 20, // number of arcs to try and fit. Does not mean that it will happen } } function display() { ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform ctx.globalAlpha = 1; // reset alpha ctx.clearRect(0, 0, w, h); if(mouse.w !== 0){ if(mouse.buttonRaw & 4){ // change arc depth if(mouse.w < 0){ arcDepth *= 1/1.05; }else{ arcDepth *= 1.05; } recalcArcs = true; }else{ // change arc count box.arcCount += Math.sign(mouse.w); box.arcCount = Math.max(4,box.arcCount); box.recalculate = true; } mouse.w = 0; } // drag out box; if(mouse.buttonRaw & 1){ if(!dragging){ box.x = mouse.x; box.y = mouse.y; dragging = true; } box.w = mouse.x - box.x; box.h = mouse.y - box.y; box.recalculate = true; if(box.w <0){ box.x = box.x + box.w; box.w = - box.w; } if(box.h <0){ box.y = box.y + box.h; box.h = - box.h; } }else{ dragging = false; } // stop error if(box.w === 0 || box.h === 0){ box.recalculate = false; } // calculate box arcs if(box.recalculate){ // reset arrays points.length = 0; arcs.length = 0; // get perimeter length var perimLen = (box.w + box.h)* 2; // get estimated step size var step = perimLen / box.arcCount; // get inset size for width and hight var wInStep = (box.w - (Math.floor(box.w/step)-1)*step) / 2; var hInStep = (box.h - (Math.floor(box.h/step)-1)*step) / 2; // fix if box to narrow if(box.w < step){ wInStep = 0; hInStep = 0; step = box.h / (Math.floor(box.h/step)); }else if(box.h < step){ wInStep = 0; hInStep = 0; step = box.w / (Math.floor(box.w/step)); } // Add points clock wise var x = box.x + wInStep; while(x < box.x + box.w){ // across top addPoint(x,box.y); x += step; } var y = box.y + hInStep; while(y < box.y + box.h){ // down right side addPoint(box.x + box.w,y); y += step; } x = box.x + box.w - wInStep; while(x > box.x){ // left along bottom addPoint(x,box.y + box.h); x -= step; } var y = box.y + box.h - hInStep; while(y > box.y){ // up along left side addPoint(box.x,y); y -= step; } // calculate arcs. for(var i =0; i <points.length; i++){ calcArc(addArc(i,(i + 1) % points.length,arcDepth)); } box.recalculate = false; } // recalculate arcs if needed for(var i = 0; i < arcs.length; i ++){ if(recalcArcs){ calcArc(arcs[i],arcDepth); } } // draw arcs drawArcStart(arcWidth,arcCol) for(var i = 0; i < arcs.length; i ++){ drawArc(arcs[i]); } drawArcDone(); recalcArcs = false; } //=========================================================================================== // END OF ANSWER // Boiler plate code from here down. Does mouse,canvas,resize and what not var w, h, cw, ch, canvas, ctx, mouse, globalTime = 0, firstRun = true; ; (function () { const RESIZE_DEBOUNCE_TIME = 100; var createCanvas, resizeCanvas, setGlobals, resizeCount = 0; createCanvas = function () { var c, cs; cs = (c = document.createElement("canvas")).style; cs.position = "absolute"; cs.top = cs.left = "0px"; cs.zIndex = 1000; document.body.appendChild(c); return c; } resizeCanvas = function () { if (canvas === undefined) { canvas = createCanvas(); } canvas.width = innerWidth; canvas.height = innerHeight; ctx = canvas.getContext("2d"); if (typeof setGlobals === "function") { setGlobals(); } if (typeof onResize === "function") { if (firstRun) { onResize(); firstRun = false; } else { resizeCount += 1; setTimeout(debounceResize, RESIZE_DEBOUNCE_TIME); } } } function debounceResize() { resizeCount -= 1; if (resizeCount <= 0) { onResize(); } } setGlobals = function () { cw = (w = canvas.width) / 2; ch = (h = canvas.height) / 2; } mouse = (function () { function preventDefault(e) { e.preventDefault(); } var mouse = { x : 0, y : 0, w : 0, alt : false, shift : false, ctrl : false, buttonRaw : 0, over : false, bm : [1, 2, 4, 6, 5, 3], active : false, bounds : null, crashRecover : null, mouseEvents : "mousemove,mousedown,mouseup,mouseout,mouseover,mousewheel,DOMMouseScroll".split(",") }; var m = mouse; function mouseMove(e) { var t = e.type; m.bounds = m.element.getBoundingClientRect(); mx = e.pageX - m.bounds.left; my = e.pageY - m.bounds.top; m.alt = e.altKey; m.shift = e.shiftKey; m.ctrl = e.ctrlKey; if (t === "mousedown") { m.buttonRaw |= m.bm[e.which - 1]; } else if (t === "mouseup") { m.buttonRaw &= m.bm[e.which + 2]; } else if (t === "mouseout") { m.buttonRaw = 0; m.over = false; } else if (t === "mouseover") { m.over = true; } else if (t === "mousewheel") { mw = e.wheelDelta; } else if (t === "DOMMouseScroll") { mw = -e.detail; } e.preventDefault(); } m.start = function (element) { if (m.element !== undefined) { m.removeMouse(); } m.element = element === undefined ? document : element; m.mouseEvents.forEach(n => { m.element.addEventListener(n, mouseMove); }); m.element.addEventListener("contextmenu", preventDefault, false); m.active = true; } m.remove = function () { if (m.element !== undefined) { m.mouseEvents.forEach(n => { m.element.removeEventListener(n, mouseMove); }); m.element.removeEventListener("contextmenu", preventDefault); m.element = m.callbacks = undefined; m.active = false; } } return mouse; })(); function update(timer) { // Main update loop if (ctx === undefined) { return; } globalTime = timer; display(); // call demo code requestAnimationFrame(update); } setTimeout(function () { resizeCanvas(); mouse.start(canvas, true); window.addEventListener("resize", resizeCanvas); requestAnimationFrame(update); }, 0); })(); 
 Left click drag to create a box<br>Mouse wheel to change arc count<br>Hold right button down and wheel to change arc depth.<br> 

使用https://www.w3schools.com/tags/canvas_beziercurveto.asp“Bezier曲线方法”制作复杂的形状。

我建议继续使用desmos并使用贝塞尔曲线弄乱,以便了解并发症。 我希望这有帮助:)

编辑:贝塞尔曲线的工作方式如下:

ctx.bezierCurveTo(控制点x,控制点y,第2控制点x,第2控制点y,完成x,完成y);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM