画出" Squiggly" javascript

时间:2015-11-25 01:36:00

标签: javascript html5 canvas

这个描述有点复杂,所以请耐心等待。

我使用HTML5画布扩展了图表工具(Diagramo)。它实现了多种类型的直线,直线,锯齿(直角)和弯曲(立方或二次)。这些线可以是实线,点线或虚线。

我正在实施的新功能是"波浪形的"线,其中而不是遵循恒定路径,线在平滑弧中在所需目标路径上来回曲折。 以下是一个正确的例子。这在大多数情况下都适用,但在某些边缘情况下则不然。 Example

实现是采用曲线,使用二次或三次函数来估计沿线的等距离点,并通过在直线的两侧放置控制点(交替)并绘制多个立方体来沿这些直线绘制波浪线曲线。

当线条相对较短时会出现问题,并且在靠近原点时会自行加倍。下面是一个例子,这种情况也发生在更长的线上 - 关键点是在原点之后有一条非常小的尖锐曲线。在这种情况下,算法选择尖锐曲线后的第一个点,在某些情况下紧邻原点,并考虑第一个段。

enter image description here

每个波浪线的最小/最大像素长度为8px / 14px(我可以更改,但远低于此值,它变得太尖锐,上面变得过于波浪状)代码试图为线条找到正确大小的波浪线段以适应最小的空白区域,然后用直线填充。

我希望有一个解决方案可以解释急剧弯曲的线条,如果我知道沿着一条线的所有点,我可以选择交替线的两侧的控制点,也垂直吗?

一种选择是考虑点i和点i-1i+1并使用它来确定线的方向,从而选择控制点吗?

代码如下

//fragment is either Cubic or Quadratic curve.
paint(fragment){
            var length = fragment.getLength();
            var points = Util.equidistancePoints(fragment, length < 100 ? (length < 50 ? 3: 5): 11);
            points.splice(0, 1); //remove origin as that is the initial point of the delegate.
            //points.splice(0, 1);
            delegate.paint(context, points);
}

/**
 *
 * @param {QuadCurve} or {CubicCurbe} curve
 * @param {Number} m the number of points
 * @return [Point] a set of equidistance points along the polyline of points
 * @author Zack
 * @href http://math.stackexchange.com/questions/321293/find-coordinates-of-equidistant-points-in-bezier-curve
 */
equidistancePoints: function(curve, m){
    var points = curve.getPoints(0.001);
    // Get fractional arclengths along polyline
    var n = points.length;
    var s = 1.0/(n-1);
    var dd = [];
    var cc = [];
    var QQ = [];
    function findIndex(dd, d){
        var i = 0;
        for (var j = 0 ; j < dd.length ; j++){
            if (d > dd[j]) {
                i = j;
            }
            else{
                return i;
            }
        }
        return i;
    };

    dd.push(0);
    cc.push(0);
    for (var i = 0; i < n; i++){
        if(i >0) {
            cc.push(Util.distance(points[i], points[i - 1]));
        }
    }
    for (var i = 1 ; i < n ; i++) {
        dd.push(dd[i-1] + cc[i]);
    }
    for (var i = 1 ; i < n ; i++) {
        dd[i] = dd[i]/dd[n-1];
    }

    var step = 1.0/(m-1);

    for (var r = 0 ; r < m ; r++){
        var d =  parseFloat(r)*step;
        var i = findIndex(dd, d);
        var u = (d - dd[i]) / (dd[i+1] - dd[i]);
        var t = (i + u)*s;
        QQ[r] = curve.getPoint(t);
    }

    return QQ;
}

SquigglyLineDelegate.prototype = {
        constructor: SquigglyLineDelegate,
        paint: function(context, points){

            var squiggles = 0;
            var STEP = 0.1;
            var useStart = false;
            var bestSquiggles = -1;
            var bestA = 0;
            var distance = Util.distance(points[0], this.start);
            for(var a = SquigglyLineDelegate.MIN_SQUIGGLE_LENGTH; a < SquigglyLineDelegate.MAX_SQUIGGLE_LENGTH; a += STEP){
                squiggles = distance / a;
                var diff = Math.abs(Math.floor(squiggles) - squiggles);
                if(diff < bestSquiggles || bestSquiggles == -1){
                    bestA = a;
                    bestSquiggles = diff;
                }
            }
            squiggles = distance / bestA;
            for(var i = 0; i < points.length; i++){
                context.beginPath();
                var point = points[i];
                for(var s = 0; s < squiggles-1; s++){
                    var start = Util.point_on_segment(this.start, point, s * bestA);
                    var end = Util.point_on_segment(this.start, point, (s + 1) * bestA);
                    var mid = Util.point_on_segment(this.start, point, (s + 0.5) * bestA);
                    end.style.lineWidth = 1;
                    var line1 = new Line(Util.point_on_segment(mid, end, -this.squiggleWidth), Util.point_on_segment(mid, end, this.squiggleWidth));
                    var mid1 = Util.getMiddle(line1.startPoint, line1.endPoint);
                    line1.transform(Matrix.translationMatrix(-mid1.x, -mid1.y));
                    line1.transform(Matrix.rotationMatrix(radians = 90 * (Math.PI/180)));
                    line1.transform(Matrix.translationMatrix(mid1.x, mid1.y));
                    var control1 = useStart ? line1.startPoint : line1.endPoint;

                    var curve = new QuadCurve(start, control1, end);
                    curve.style = null;
                    curve.paint(context);
                    useStart = !useStart;
                }
                this.start = point;
                context.lineTo(point.x, point.y);
                context.stroke();
            }
        }
    }

0 个答案:

没有答案