Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/465.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript HTML5画布中的手绘圆模拟_Javascript_Jquery_Canvas_Html5 Canvas - Fatal编程技术网

Javascript HTML5画布中的手绘圆模拟

Javascript HTML5画布中的手绘圆模拟,javascript,jquery,canvas,html5-canvas,Javascript,Jquery,Canvas,Html5 Canvas,使用jQuery在HTML 5画布中创建一个圆: 代码: //get a reference to the canvas var ctx = $('#canvas')[0].getContext("2d"); DrawCircle(75, 75, 20); //draw a circle function DrawCircle(x, y, radius) { ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI*2, true);

使用jQuery在HTML 5画布中创建一个圆:

代码:

//get a reference to the canvas
var ctx = $('#canvas')[0].getContext("2d");

DrawCircle(75, 75, 20);

//draw a circle
function DrawCircle(x, y, radius)
{
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, Math.PI*2, true); 
    ctx.fillStyle = 'transparent';
    ctx.lineWidth = 2;
    ctx.strokeStyle = '#003300';
    ctx.stroke();
    ctx.closePath();
    ctx.fill();
}
我尝试模拟以下任何类型的圆:

我已经研究并发现了这个,但无法应用它

我想画一个圆圈,而不是仅仅出现

有更好的方法吗?我感觉会涉及很多数学问题:)


另外,我喜欢的简单,也许这是使用其简化路径的最简单方法?

您的任务似乎有3个要求:

  • 手绘的形状
  • “有机”而非“超精确”笔划
  • 逐步显示圆,而不是一次显示所有圆
  • 要开始,请查看Andrew Trice的这个漂亮的目标演示

    这个神奇的圆圈是我亲手画的(你现在可以笑了…!)

    Andrew的演示完成了您需求的第1步和第2步

    它可以让你用一种有机的“画笔效果”手工画一个圆(或任何形状),而不是通常在画布上使用的超精密线条

    它通过在手绘点之间重复绘制画笔图像来实现“画笔效果”

    下面是演示:

    代码可在GitHub上获得:

    Andrew Trice的演示画出并忘记了构成圆圈的线条

    您的任务是实现第三个要求(记住笔划):

    • 亲手画一个圆圈
    • 将构成圆的每个线段保存在一个数组中
    • 使用安德鲁风格化的画笔技术“播放”这些片段
    结果:一个手绘和样式化的圆圈,以增量方式显示,而不是一次全部显示


    你有一个有趣的项目…如果你觉得慷慨,请分享你的结果

    以下是我为这个答案创建的一些基础知识:

    基本上,当你画一个圆时,你需要考虑手的缺陷。因此,在以下代码中:

    var img = new Image();
    img.src="data:image/png;base64,...";
    
    var ctx = $('#sketch')[0].getContext('2d');
    function draw(x,y) {
      ctx.drawImage(img, x, y);
    }
    
    for (var i=0; i<500; i++) {
        var radiusError = +10 - i/20;
        var d = 2*Math.PI/360 * i;
        draw(200 + 100*Math.cos(d), 200 + (radiusError+80)*Math.sin(d) );
    }
    
    显然,圆心位于(200200),因为用三角函数绘制圆的公式是

    x = centerX + RX * cos ( angle )
    y = centerY + RY * sin ( angle )
    

    这里已经有了很好的解决方案。我想添加一个已经呈现的变体-如果想要模拟手绘的圆,除了一些三角学之外没有太多的选项

    我首先建议实际记录一个真实的手绘圆圈。您可以记录这些点以及
    时间戳
    ,并在以后的任何时候复制精确的图形。您可以将其与线平滑算法相结合

    此解决方案在此处生成如下圆圈:

    您可以像往常一样通过设置
    笔划样式
    线宽
    等来更改颜色、厚度等

    要画一个圆圈,只需调用:

    handDrawCircle(context, x, y, radius [, rounds] [, callback]);
    
    回调
    是在动画使函数异步时提供的)

    代码分为两部分:

  • 生成点
  • 设置点的动画
  • 初始化

    function handDrawCircle(ctx, cx, cy, r, rounds, callback) {
    
        /// rounds is optional, defaults to 3 rounds    
        rounds = rounds ? rounds : 3;
    
        var x, y,                                      /// the calced point
            tol = Math.random() * (r * 0.03) + (r * 0.025), ///tolerance / fluctation
            dx = Math.random() * tol * 0.75,           /// "bouncer" values
            dy = Math.random() * tol * 0.75,
            ix = (Math.random() - 1) * (r * 0.0044),   /// speed /incremental
            iy = (Math.random() - 1) * (r * 0.0033),
            rx = r + Math.random() * tol,              /// radius X 
            ry = (r + Math.random() * tol) * 0.8,      /// radius Y
            a = 0,                                     /// angle
            ad = 3,                                    /// angle delta (resolution)
            i = 0,                                     /// counter
            start = Math.random() + 50,                /// random delta start
            tot = 360 * rounds + Math.random() * 50 - 100,  /// end angle
            points = [],                               /// the points array
            deg2rad = Math.PI / 180;                   /// degrees to radians
    
    在主循环中,我们不会随机反弹,而是使用随机值递增,然后使用该值线性递增,如果处于边界(公差),则反转该值

    提示:要获得更真实的笔划,您可以将
    globalAlpha
    减少到例如
    0.7

    但是,要使其正常工作,您需要先将实体绘制到屏幕外画布,然后将屏幕外画布blit到主画布(设置了
    globalAlpha
    ),否则笔划将在每个点之间重叠(看起来不太好)

    对于正方形,可以使用与圆相同的方法,但不使用半径和角度,而是将变化应用于直线。偏移增量以使直线不直

    我稍微调整了值,但可以随意调整它们以获得更好的结果

    要使圆稍微“倾斜”,可以先稍微旋转画布:

    rotate = Math.random() * 0.5;
    
    ctx.save();
    ctx.translate(cx, cy);
    ctx.rotate(-rotate);
    ctx.translate(-cx, -cy);
    
    循环结束时:

    if (i < points.length) {
        requestAnimationFrame(draw);
    } else {
       ctx.restore();
    }
    
    然后当动画完成时:

    if (i < points.length) {
        requestAnimationFrame(draw);
    
    } else {
        ctx.restore();
        if (typeof callback === 'function')
            callback();  /// call next function
    }
    
    if(i
    您将遇到的另一个问题是代码本身(请记住,代码只是一个示例,而不是完整的解决方案:-)),这是一个粗线条:

    当我们单独逐段绘制时,canvas不知道如何计算直线相对于前一段的对接角度。这是路径概念的一部分。当您使用多个线段绘制路径时,画布将知道对接(线的端点)的角度。因此,这里我们要么从起点到当前点画一条线,并在中间进行清除,要么只画一个较小的
    线宽值

    当我们使用<代码> CurrCutt < /C> >(这将使线条平滑而不是“锯齿状”,因为当我们不使用一个透明的,但只是在上面画上)时,我们需要考虑实现一个顶部的画布来完成动画,当动画完成时,我们将结果绘制到主画布上。 现在我们开始看到其中的“复杂性”。这当然是因为canvas是“低级的”,即我们需要为所有事物提供所有逻辑。我们基本上是在每次使用画布做更多的事情时构建系统,而不仅仅是绘制简单的形状和图像(但这也提供了极大的灵活性)。

    也可以作为


    功能路径(δr_min,δr_max,el0_min,el0_max,δel_min,δel_max){
    var c=0.551915024494;
    var atan=Math.atan(c)
    VarD=Math.sqrt(c*c+1*1),r=1;
    var el=(el0_min+Math.random()*(el0_max-el0_min))*Math.PI/180;
    var路径='M';
    路径+=[r*Math.sin(el
    
    rotate = Math.random() * 0.5;
    
    ctx.save();
    ctx.translate(cx, cy);
    ctx.rotate(-rotate);
    ctx.translate(-cx, -cy);
    
    if (i < points.length) {
        requestAnimationFrame(draw);
    } else {
       ctx.restore();
    }
    
    handDrawCircle(context, x, y, radius [, rounds] [, callback]);
    
    if (i < points.length) {
        requestAnimationFrame(draw);
    
    } else {
        ctx.restore();
        if (typeof callback === 'function')
            callback();  /// call next function
    }
    
    <div id="container">
        <svg width="100%" height="100%" viewBox='-1.5 -1.5 3 3'></svg>
    </div>
    
    #container {
      width:500px;
      height:300px;
    }
    path.ln {
      stroke-width: 3px;
      stroke: #666;
      fill: none;
      vector-effect: non-scaling-stroke;
      stroke-dasharray: 1000;
      stroke-dashoffset: 1000;
      -webkit-animation: dash 5s ease-in forwards;
      -moz-animation:dash 5s ease-in forwards;
      -o-animation:dash 5s ease-in forwards;
      animation:dash 5s ease-in forwards;
    }
    
    @keyframes dash {
      to { stroke-dashoffset: 0; }
    }
    
    function path(δr_min,δr_max, el0_min, el0_max, δel_min,δel_max) {
    
        var c = 0.551915024494;
        var atan = Math.atan(c)
        var d = Math.sqrt( c * c + 1 * 1 ), r = 1;
        var el = (el0_min + Math.random() * (el0_max - el0_min)) * Math.PI / 180;
        var path = 'M';
    
        path += [r * Math.sin(el), r * Math.cos(el)];
        path += ' C' + [d * r * Math.sin(el + atan), d * r * Math.cos(el + atan)];
    
        for (var i = 0; i < 4; i++) {
            el += Math.PI / 2 * (1 + δel_min + Math.random() * (δel_max - δel_min));
            r *= (1 + δr_min + Math.random()*(δr_max - δr_min));
            path += ' ' + (i?'S':'') + [d * r * Math.sin(el - atan), d * r * Math.cos(el - atan)];
            path += ' ' + [r * Math.sin(el), r * Math.cos(el)];
        }
    
        return path;
    }
    
    function cX(λ_min, λ_max, el_min, el_max) {
        var el = (el_min + Math.random()*(el_max - el_min));
        return 'rotate(' + el + ') ' + 'scale(1, ' + (λ_min + Math.random()*(λ_max - λ_min)) + ')'+ 'rotate(' + (-el) + ')';
    }
    
    function canvasArea() {
        var width = Math.floor((Math.random() * 500) + 450);
      var height = Math.floor((Math.random() * 300) + 250);
        $('#container').width(width).height(height);
    }
    d3.selectAll( 'svg' ).append( 'path' ).classed( 'ln', true) .attr( 'd', path(-0.1,0, 0,360, 0,0.2 )).attr( 'transform', cX( 0.6, 0.8, 0, 360 ));
    
    setTimeout(function() { location = '' } ,5000)