码迷,mamicode.com
首页 > 其他好文 > 详细

2014/09/16 – Canvas & Bezier

时间:2014-09-16 18:37:30      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   ar   for   2014   

都是 Canvas.setLineDash 惹的祸,就因为他是草案,所以有些浏览器还不支持。

需求: 画虚线。

分析:线包括直线与曲线。直线的虚线很好实现就不多说了,主要说下曲线的实现,即(3次)贝塞尔曲线的实现。

思路:1. 根据像素粒度值计算出3次贝塞尔曲线的点集合(参考wiki);

   2. 根据求得的点集合,进行虚线的绘制; (难点是根据传入参数 dash list 进行像素点筛选)

code:

var DashedBezier = function (ctx, points, dashList, options) {
            this.ctx = ctx;
            this.points = points;
            this.dashList = dashList;
            this.options = $.extend( {
                particleSize: 100,
                strokeStyle: "#000",
                lineWidth: "1"
            }, options || {});
        };
        DashedBezier.prototype = {
            constructor: DashedBezier,
            _pointOnCubicBezier: function (cp, t) {
                var ax, bx, cx;
                var ay, by, cy;
                var tSquared, tCubed;
                var result = { x: 0.0, y: 0.0 };

                /*計算多項式係數*/

                cx = 3.0 * (cp[1].x - cp[0].x);
                bx = 3.0 * (cp[2].x - cp[1].x) - cx;
                ax = cp[3].x - cp[0].x - cx - bx;

                cy = 3.0 * (cp[1].y - cp[0].y);
                by = 3.0 * (cp[2].y - cp[1].y) - cy;
                ay = cp[3].y - cp[0].y - cy - by;

                /*計算位於參數值t的曲線點*/

                tSquared = t * t;
                tCubed = tSquared * t;

                result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
                result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;

                return result;
            },
            _computeBezier: function (cp, numberOfPoints) {
                var dt;
                var i;
                var curve = [];

                dt = 1.0 / (numberOfPoints - 1);

                for (i = 0; i < numberOfPoints; i++)
                    curve[i] = this._pointOnCubicBezier(cp, i * dt);

                return curve;
            },
            _bezier: function (controlPoints, t) {
                return [controlPoints[t].x, controlPoints[t].y];
            },
            _calculateDashedBezier: function (controlPoints, dashPattern) {
                var step = 1; //this really should be set by an intelligent method,
                //rather than using a constant, but it serves as an
                //example.

                //possibly gratuitous helper functions
                var delta = function (p0, p1) {
                    return [p1[0] - p0[0], p1[1] - p0[1]];
                };
                var arcLength = function (p0, p1) {
                    var d = delta(p0, p1);
                    return Math.sqrt(d[0] * d[0] + d[1] * d[1]);
                };

                var subPaths = [];
                var loc = this._bezier(controlPoints, 0);
                var lastLoc = loc;

                var dashIndex = 0;
                var length = 0;
                var thisPath = [];
                for (var t = step; t < 100; t += step) {
                    loc = this._bezier(controlPoints, t);
                    length += arcLength(lastLoc, loc);
                    lastLoc = loc;

                    //detect when we come to the end of a dash or space
                    if (length >= dashPattern[dashIndex]) {

                        //if we are on a dash, we need to record the path.
                        if (dashIndex % 2 == 0)
                            subPaths.push(thisPath);

                        //go to the next dash or space in the pattern
                        dashIndex = (dashIndex + 1) % dashPattern.length;

                        //clear the arclength and path.
                        thisPath = [];
                        length = 0;
                    }

                    //if we are on a dash and not a space, add a point to the path.
                    if (dashIndex % 2 == 0) {
                        thisPath.push(loc[0], loc[1]);
                    }
                }
                if (thisPath.length > 0)
                    subPaths.push(thisPath);
                return subPaths;
            },
            _pathParts: function (ctx, pathParts) {
                var isMove = false;
                for (var i = 0; i < pathParts.length; i++) {
                    if (pathParts[i].length !== 0) {
                        if (!isMove) {
                            ctx.moveTo(pathParts[i][0], pathParts[i][1]);
                        } else {
                            ctx.lineTo(pathParts[i][0], pathParts[i][1]);
                        }
                        isMove = !isMove;
                    }
                    //var part = pathParts[i];
                    //if (part.length > 0)
                    //    ctx.moveTo(part[0], part[1]);
                    //for (var j = 1; j < part.length / 2; j++) {
                    //    ctx.lineTo(part[2 * j], part[2 * j + 1]);
                    //}
                }
            },
            _drawDashedBezier: function (ctx, controlPoints, dashPattern) {
                var dashes = this._calculateDashedBezier(controlPoints, dashPattern);
                ctx.beginPath();
                ctx.strokeStyle = this.options.strokeStyle;
                ctx.lineWidth = this.options.lineWidth;
                this._pathParts(ctx, dashes);
                ctx.stroke();
            },
            set_Points: function (points) {
                this.points = points;
            },
            draw: function (ctx) {
                ctx && (this.ctx = ctx);
                var cp = [{ x: this.points[0], y: this.points[1] },
                    { x: this.points[2], y: this.points[3] },
                    { x: this.points[4], y: this.points[5] },
                    { x: this.points[6], y: this.points[7] }],
                    curve = this._computeBezier(cp, this.options.particleSize);

                this._drawDashedBezier(this.ctx, curve, this.dashList);
            }
        };

call:

bubuko.com,布布扣
var dashedBezierInstance = new DashedBezier(
            document.getElementById("dashCanvas").getContext("2d"),
            [0, 150, 75, 50, 225, 200, 300, 150],
            [2, 7],
            {
                strokeStyle: "#cc0000"
            });
        dashedBezierInstance.draw();
call main

html:

bubuko.com,布布扣
<canvas width="400" height="300" id="dashCanvas"></canvas>
index.html

2014/09/16 – Canvas & Bezier

标签:style   blog   http   color   io   os   ar   for   2014   

原文地址:http://www.cnblogs.com/yoyoone23/p/3975296.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!