2017-02-25 107 views
3

我真的很需要幫助,關於如何使用帆布創建扇貝形狀 我嘗試過圍繞雲樣本玩耍,但創建我想要的東西真的很困難。HTML5帆布扇貝形狀

我只是想知道矩形和圓形扇貝形狀的代碼。

這是我想要的圖像。 Scallop Design

它的設計不必完全一樣,但儘可能它看起來像這樣。

謝謝你這麼多,在ADVANCEEE ..

回答

1

使用https://www.w3schools.com/tags/canvas_beziercurveto.asp「貝塞爾曲線法」,使複雜的形狀。

我建議去desmos和亂搞bezier曲線,以瞭解併發症。我希望這有助於:)

編輯:貝塞爾曲線的工作是這樣的:

ctx.bezierCurveTo(控制點X,控制點y,第二個控制點的x,第二個控制點y,整理X,整理Y) ;

+0

哇,這是相當複雜的。 – Khyana

+0

@DownCrow對不起,但它是唯一的方法。相信我,一旦你掌握了它,它是超級容易的。 :) –

+0

我看,我在哪裏可以找到這裏的代碼> – Khyana

2

你可以使用虛線畫出這樣的形狀,像這樣(有點棘手)。

的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

+0

爲什麼你不使用二次曲線? –

+0

在這種情況下,我的代碼不需要二次曲線。但是使用二次曲線是比較一般的,因爲我的代碼很難操縱筆畫寬度輪廓的形狀。 – defghi1977

2

從較早的答案,但問題是很模糊的,有很多額外的行李。以下是該答案的一個片段。它有一些額外的代碼,可能有幫助但不直接相關。

功能顯示(大約一半向下)完成大部分工作,將弧添加到對象框。

看到指令

運行演示

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(); 
 
      m.x = e.pageX - m.bounds.left; 
 
      m.y = 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") { 
 
       m.w = e.wheelDelta; 
 
      } else if (t === "DOMMouseScroll") { 
 
       m.w = -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>

+0

謝謝你,我也在這裏看到過這個帖子。 但我不想自由繪製它。我只是想展示它。所以基本上我想要一個固定扇貝形狀的代碼。 – Khyana

+0

Han this *「按住右鍵並轉動圓弧來改變弧深。」*用觸控板是不可能的......您可以將它改爲*「用左腳撫摸您的鼻子時挺直」*而不是? – Kaiido