CAT | Web

乱贴图:没呼也来,挥之不去的大雾,笼罩着一切,让我看不清到底通向什么地方
如往常一样,一周到了某个时候,就会打开下载站点,寻觅是否有感兴趣的新资源下载,通常是美剧。与之相对,我亲爱的同事们都流行直接在线看,只要网速足够。另外花时间下载,要关心下载进度,还要关心资源下载好之后的存放等一个一个事情,虽小,但是与在线观看相比,还是显得那么的多余。
呼之即来,挥之则去的感觉是挺爽的。
我也一直在思考那么一种构建方式,Web 应用程序由模块组成,页面上运行的脚本可以按需加载所需要的模块,不过暂时只是在某个程度上实现,还未达到所想要的效果。想要呼之则来,还是没那么容易的,更别谈挥之则去了,幸好目前还没有那样的需求。
可以想象,如果可以稳定地实现按需加载(不仅仅是脚本,所有页面上需要用到的资源),很多有趣的功能都变得有可能了。看来要好好地做做研究,看看现在到底在处理这方面问题时有什么样的方案,什么样的技术来支持。
什么时候才能达到想要的效果呢?或许还需要浏览器进一步进化,增强脚本的功能。
想吧,想吧,继续想吧。

Bezier Curve in Canvas
只是靠直线和弧线来画图是不够的,面对一些更加复杂但是有规律的图形时,我们需要另外一个更加强而有力的工具——贝塞尔曲线。
在 canvas 里,贝塞尔曲线有二次方和三次方两种形式,区别就在于控制点的数目,二次方的只有一个控制点,而三次方的则有两个。
quadraticCurveTo(cp1x, cp1y, x, y) bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
这里的贝塞尔曲线的用法同样的很简单的,但是却不像在 Photoshop 或者 Illustrator 里画曲线那么轻巧了,它是非常需要触觉和耐心的。所以上面强调了有规律这个关键词。
实际上是什么感觉,大家亲身体验吧,看看下面的示例。
var colors = ["ec460c", "1e951e", "2692f7", "ea62f6"];
var cp1 = 60;
var cp2 = 160;
var y1 = 150;
for (var i=0; i< colors.length; i++) {
ctx.beginPath();
ctx.moveTo(25,75);
ctx.bezierCurveTo(85,75,cp1,y1,100,y1);
ctx.bezierCurveTo(cp2,y1,120,35,190,35);
cp1 -= 10; // 使控制点 1 横坐标左移 10 像素
cp2 += 10; // 使控制点 2 横坐标右移 10 像素
y1 += 20; // 是曲线低点下降 20 像素
ctx.strokeStyle = "#" + colors[i];
// 设置线条颜色
ctx.stroke();
}
如图,我比较懒,里面用了循环画了几条曲线,一阵颜色一条,不同在于曲线的底端位置与曲线口径的不同。
你觉得像个什么呢?
这里并没有用到二次方形式的贝塞尔曲线,但是三次方的都会用了,二次方的还不行吗?
PS: 以上代码是主体部分,要运行上面的例子,请参考 进驻Canvas
也不是第一次拿 IE 说事了,不过这次 IE 的 bug 还是有点意思的,也看到过有人提及这个 bug,解决的方法就是在CSS里设置它的 width 或者 height,要看具体的应用场景了,好像下面的这个例子。
<div class="composite">
<div class="item">AAA</div>
<div class="item">BBB</div>
<div class="item">CCC</div>
<div class="item">DDD</div>
</div>
<style type="text/css">
.composite {
background-color:#CCC;
padding: 0 0 0 40px;
}
.item {
background-color: #666;
padding: 0;
}
</style>
简单得就是两层 div,有深浅不同的灰色背景。当里面那层 div 只包含像 text、input 这类的元素(我暂时还不致于无聊到逐一去尝试)时,它的背景色就不显示的,不过也不是永远不显示。

DIV no background in IE
有趣在这里。当你用另外一个窗口,例如 QQ 聊天窗口,在上面移来移去,哈哈,那个背景色出现了,但只是一部分——被重绘的那部分,当时给一个同事看的时候,他还问:这是怎么实现的啦……
囧!!

DIV 的背景出现在重绘之后
目前我还没想明白到底是为啥出现这种状况。解决的方法也是相当的离奇,不知道是 IE 的 box model 的问题还是什么,不过通过设置 width 和 height 可以解决 IE 不止一个 bug,大概不会是 IE 计算区域的占地面积而造成的吧!
.exprItem {
background-color: #666;
_height: 1px;
padding: 0;
}
上面通过一个 CSS hack 是其中一个解决方法,这种写法只有 IE 认得出来。因为通常情况下,我都希望元素自己去管理其领地而不要来问我应该拨多少地。
* IE version is 6.0.2900.2180.xpsp_sp2_gdr.080814-1233
在 canvas 里绘制弧线也是非常简单的。
arc(x, y, radius, startAngle, endAngle, anticlockwise)
x, y 是圆心坐标,radius 是圆弧的半径,startAngle,endAngle分别是弧线起点和终点的弧度,注意,是弧度,而不是度,它们之间可以通过
function radian(degrees) {
return (Math.PI/180)*degrees
}
来进行转换。最后 anticlockwise 用于指示弧线绘制的方向,true 时表示逆时针方向。
var canvas = document.getElementById('myCanvas');
var size = 220;
canvas.width = canvas.height = size;
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var X = size/2;
var Y = size/2;
var N = 12;
var R = 80;
for (var i=1; i<=12; i++) {
var r = 20;
var startAngle = 0 - Math.PI/2;
var endAngle = radian(360*(i/N)) - Math.PI/2;
var x = X + R*Math.cos(endAngle);
var y = Y + R*Math.sin(endAngle);
var anticlockwise = false;
ctx.beginPath();
ctx.arc(x, y, r, startAngle, endAngle, anticlockwise);
Math.cos(endAngle + Math.PI/2) > 0 ? ctx.stroke(): ctx.fill();
}
}

Arc
这样一个按顺时针变化的大圆就完成了。
完成上面的例子大概需要一点基础数学知识。
可以随意改变里面的圆的半径和起始、结束弧度又或者最后的控制填充与描边的算式来感受一下那种变化。
在了解 如何绘制 canvas 里唯一的基本形状——矩形 之后,现在可以转入使用路径了。路径不仅仅是线条,只是习惯性的会从线条开始,而直线可算是最简单的线条了。
使用路径,是有套路的。
创建、绘制、关闭和填充或者勾勒形状。
beginPath() // actual drawing closePath() stroke() fill()
两点确定一条直线,在 canvas 里也不例外的。
lineTo(x, y)
x, y 只是终点的坐标,起点坐标是隐含的,并且取决于前一操作。简单来说,上一操作的终点就是当前直线的起点。新建 canvas 时起点就是原点。另外还可以通过这个方法:
moveTo(x, y)
来移动起始坐标。moveTo 顾名思义就是移动坐标用的,它一般用于重设起始坐标,大多数情况下路径都不是起于原点的,而且在绘制一些不连续的路径时非常有用。
var x = 60; var y = 20; var r = 40; var dy = Math.sqrt((r*2)*(r*2)-r*r); ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x-r, y+dy); ctx.lineTo(x+r, y+dy); ctx.fill(); var y = y + 2*(Math.sqrt(4/3)*r); ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(x-r, y-dy); ctx.lineTo(x+r, y-dy); ctx.closePath(); ctx.stroke();

2-triangles
上面的代码绘制出六角星,moveTo 这里是移动起始坐标又用于创建两条不连续的三角路径。
三角几何的内容就不解析了,重点是使用填充和描边的区别。填充是会触发路径的自动闭合的,而描边则不会。
这里可以看出在这个套路里 closePath 不是必须的。如果描边之前不闭合路径,所勾画出来的将会是开放的路径,在这个案例里就是只画两边。
canvas · html · javascript
在canvas的世界里,只有一种基本图形——矩形,听起来很难以想象啊,复杂的图形怎么办呢?很多时候复杂问题总有简单的解法的。杀手锏就是路径,用路径和路径组合就可以绘制出相当复杂的图形,很浓重的矢量味道噢。像在 Illustrator 这类矢量设计软件里,路径就是一切的基础。是不是意味着,canvas 同样是矢量世界呢?
还是先搞定仅有的一种基本图形吧。最简单不过下面三个函数:
// 绘制一个方块 fillRect(x,y,width,height) // 绘制一个矩形轮廓 strokeRect(x,y,width,height) // 清出一个透明的矩形区域 clearRect(x,y,width,height)
其中x,y是矩形区域左上角的位置。
function draw() {
var canvas = document.getElementById('myCanvas');;
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.fillRect(15, 15, 120, 120);
ctx.clearRect(40, 40, 70, 70);
ctx.strokeRect(45, 45, 60, 60);
ctx.strokeRect(50, 50, 50, 50);
}
}

Rectangle in canvas
在 canvas 上,首先填充了一个 120×120 的黑色(默认色)方块,清出中间并在其内勾画出双边矩形,看上去和右边的图形是一致的。
是由点组成的,但一开始就绘制面了,那么如何绘制点呢?其实,屏幕上的像素点也是一个矩形,画一个 1×1 的矩形就是点了。用 fillRect 和 strokeRect 都可以,但是有一点区别,fillRect 可以准确的填充出一个像素点,而用 strokeRect 则可以得到一个视觉上的点,边缘是模糊的。同样,如果希望矩形块的边缘是锐利的,使用 fillRect 而不是 strokeRect 。
在show图片的时候经常需要用到它,大概是大家都比较懒去为每个图调整大小,用Photoshop的批处理是可以省掉很多功夫了,但为求更省事,用脚本啦。
<img id="inu" src="your-image-path.jpg" onload = "resize(this)" />
在页面里插一行就可以了(resize函数体在下面),如果图像是动态装载的
var img = document.createElement('img');
img.onload = resize;
img.src = "http://farm4.static.flickr.com/3575/3343323074_499a81709c_o.png";
var MAX_IMAGE_SIZE = {
x: 400,
y: 400
};
function resize(obj) {
var img = obj || this;
var size = MAX_IMAGE_SIZE;
var rate = img.offsetWidth / img.offsetHeight;
if (img.offsetWidth > size.x) {
img.style.width = size.x + "px";
img.style.height = size.x / rate + "px";
}
if (img.offsetHeight > size.y) {
img.style.width = size.y * rate + "px";
img.style.height = size.y + "px";
}
// 如果有需要居中的话,用CSS也可以实现
reCenter(img, size);
}
function reCenter(img, size) {
if (img.offsetHeight < size.y) {
img.style.marginTop = (size.y - img.offsetHeight)/2 + "px";
}
if (img.offsetWidth < size.x) {
img.style.marginLeft = (size.x - img.offsetWidth)/2 + "px";
}
}
网上也有不少说onload事件在不同浏览器里的不同现象,Netscape(国内没什么人用了吧) 和 IE不是每次都触发onload事件,只有从网上下载时才执行,从缓存里装载后不执行。
那应该是因为设置onload在设置src之后,设置src后浏览器随即从缓存里装载好了,那时再指定onload为时已晚了,但在Firefox里在前在后都始终如一。最稳是在src之前设置onload属性。
html · img · javascript
<canvas>首先是在Mac OS X Dashboard上出现的,随后是safari,接着是基于Gecko的Firefox 1.5 … 而现在更被WhatWG 接纳,成为WhatWG Web applications 1.0 specification即 HTML 5 的一部分。
canvas可以用来画图,合成图像甚至是做动画,使用canvas不难,会HTML和JavaScript就可以很快的开进了。不过基本上,我觉得最终目标是动画效果和实现交互,那应该多少需要一点知识和经验,例如数学知识,颜色知识,交互经验等等……当然还需要想象力和最重要的——耐心。
之前在Canvas的奇怪变形也说过用css来定义canvas的长宽会引起变形,那个变形在不同的浏览器里面还不一样,实在无聊了可以试试,不过,最稳还是指定canvas的width和height属性。
<canvas>这个新的HTML元素的吸引力真是让我无法抵挡。在看过一些令人惊异的效果之后,canvas随即成为了最近的研究课题之一。
首先需要一个浏览器,Firefox (1.5 以上)这类基于Gecko的浏览器、Safari、Chrome和Opera都支持它, IE不支持。
在新建的页面里面加入
<canvas id="myCanvas" width="300" height="150"></canvas>
myCanvas 其实只是一个容器,内容的填充就是脚本(通常是javascript)出场的时候了。
var canvas = document.getElementById('myCanvas');
if (canvas.getContext){
var ctx = canvas.getContext('2d');
// drawing code here
} else {
// canvas-unsupported code here
}
我觉得既然要测试canvas,当然不会选一个不支持它的浏览器来玩,但是检查特性是否被支持是一个良好的习惯,正式使用时大可以通过代码重构将这一些框框隐藏起来。
然后画一个很常见的图吧,保存代码为html再用浏览器打开,看到什么了?
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script language="javascript" type="text/javascript">
function drawRGB() {
var canvas = document.getElementById('myCanvas');;
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var x = y = 60;
var r = 20; // 半边长
var dy = Math.sqrt((r*2)*(r*2)-r*r); // 显而易见
var radius = 30;
var startAngle = 0;
var endAngle = Math.PI*2;
var anticlockwise = true;
var list = [
// 红
{'x': x, 'y': y, 'color': "rgb(255,0,0)"},
// 绿 透明0.6
{'x': x-r, 'y': y+dy, 'color': "rgba(0,255,0,0.6)"},
// 蓝 透明0.6
{'x': x+r, 'y': y+dy, 'color': "rgba(0,0,255,0.6)"}
]; // 三个圆的圆心位置及其颜色
for (var i=0; i<list.length; i++) {
var item = list[i];
ctx.beginPath(); // 开启新路径
ctx.fillStyle = item.color; // 设置填充样式
// 画圆形路径
ctx.arc(item.x, item.y, radius,
startAngle, endAngle, anticlockwise);
// 填充
ctx.fill();
}
}
}
</script>
</head>
<body onload="drawRGB();">
<canvas id="myCanvas" width="300" height="150"></canvas>
</body>
</html>
解释见注释
未完待续…
我一般用脚本创建元素的同时多数会附加css来控制大小,背景色,etc.
但在<canvas>上却表现比较怪,
var canvas = new Element('canvas', {styles: {width: '150px',height : '150px'}});
再在上面画东西的时候居然发现变形了
我记得mozilla上面说是可以改变它的大小的
分析一下,canvas最终表现和一个png图像差不多,而它的默认大小是300/150,当应用css时,相当于宽度压缩了。
那不用css怎么办呢?其实很简单
var canvas = new Element('canvas', {width: 150,height : 150});
诶,被css惯坏了……
注: Element指的是mootools里的那个


