前端乱炖 | code for yourself! no one else!

如何用程序触发window的onscroll事件

很多延迟加载的组件监听的都是window.onscroll事件.所以如果你自己模拟滚动条的话,你需要在滚动到时候能用js触发这个事件.

如何做呢,直接上代码,不要问为什么,就是这样:

if (document.createEvent)
            {
                var evObj = document.createEvent("HTMLEvents")
                evObj.initEvent( "scroll", true, false )
                window.dispatchEvent(evObj)
            }else{
                document.body.click();
            }

ie里面有人说用scrollTo或者scrollBy可以触发....不错,不过如果你的鼠标左键被按下或者滚轮在滚动,这种方法就失效了....为什么我也不知道.
后来发现只需要点击一下body...就能触发onscroll....注意是window的onscroll...其他元素的可能存在不同.

No tags

贝塞尔曲线的更正和一些方法

之前写过一篇关于贝塞尔曲线的文章,写的很复杂,用矩阵算出的贝塞尔,今天在使用的时候发现是有错误的.

所以重新写了一个方法,比矩阵简单的多:

资料:http://paulbourke.net/geometry/bezier/index2.html

前提:定义一个向量类,主要用来标识点坐标,所以叫 Point:

(function(){
    var p=SCD.Point;
    SCD.Point=function(x,y){
        this.x=x||0;
        this.y=y||0;
    }

    SCD.Point.prototype={
        /*~!Vector*/
        toArray:function(){
            return [this.x,this.y]
        },
        add:function(v){
            return new SCD.Point(this.x+v.x,this.y+v.y);
        },
        sub:function(v){
            return new SCD.Point(this.x-v.x,this.y-v.y);
        },
        getMod:function(){
            return Math.sqrt(this.x*this.x+this.y*this.y);
        },
        mulNum:function(num){
            return new SCD.Point(this.x*num,this.y*num);
        },
        getNegative:function(){
            return new SCD.Point(-this.x,-this.y);
        },
        /**
         *返回一个常数代表b在a上的投影乘以a的长度
         */
        dotMul:function(v){
            return this.x*v.x+this.y*v.y;
        },
        crossMul:function(v){
            return   this.x*v.y-this.y*v.x;
        },
        /**
         *获取夹角,注意返回的是角度
         */
        getAngle:function(v){
            return Math.acos(this.dotMul(v)/(this.getMod()*v.getMod()))* 180/Math.PI;

        },
        /**
         *获取夹角,返回的是弧度
         */
        getRadian:function(v){
            var m1=this.getMod(),m2=v.getMod();
            if(m1==0||m2==0){
                return 0;
            }
            return Math.acos(this.dotMul(v)/(m1*m2));
        },
        distance:function(v){
            return Math.sqrt((this.x-v.x)*(this.x-v.x)+(this.y-v.y)*(this.y-v.y))
        },
        distance2:function(v){
            return (this.x-v.x)*(this.x-v.x)+(this.y-v.y)*(this.y-v.y)
        },
        /**
         *求某向量的法向量,返回一个单位向量,其模为1,返回的向量总是指向this向量的右边
         * @return
         */
        getNormal:function(){
            return new SCD.Point(this.y/(Math.sqrt(this.x*this.x+this.y*this.y)),-this.x/(Math.sqrt(this.x*this.x+this.y*this.y)));
        },
        reflex:function(v){
            var normal=v.getNormal();//先求法向量
            var angle=this.getAngle(normal);//求与法线的夹角
            return this.sub(normal.mulNum(2*this.dotMul(normal)));
        },
        mirror:function(v){
            return this.reflex(v).getNegative();
        },
        isZero:function(){
            if(this.x==0&&this.y==0) return true;else return false;
        },
        /**
         *判断某个点是否在某个矩形区域里,如果在里面的话,并且存在第四个参数的话(true),
         *就继续判断相对矩形中心点所在象限,最后返回象限,不存在第四个参数返回-1
         *如果不在矩形区域里,就直接返回false
         *
         *@param {vector} t 矩形左上角坐标
         *@param {vector} b 矩形右下角坐标
         *@param {boolean} q 是否返回象限
         *@return {number} 象限或者-1
         */
        isIn:function(t,b,q){
            var r1=this.sub(t),r2=this.sub(b)
            if(r1.x>=0&&r1.y>=0&&r2.x<=0&&r2.y<=0){
                if(q){
                    var c=t.add(b).mulNum(0.5)
                    return this.getQ(c)
                }else{
                    return -1;
                }
            }else{
                return false;
            }
        },
        /**
         *获取第一个点相对第二个点所在的象限
         *
         *@param {vector} pc 第二个点的坐标
         */
        getQ:function(pc){
            var r=this.sub(pc);
            if(r.x>=0&&r.y>=0){
                return 4
            }else if(r.x<0 &&r.y>=0){
                return 3
            }else if(r.x<0&&r.y<0){
                return 2
            }else if(r.x>=0&&r.y<0){
                return 1
            }
        },
        toString:function(){
            return this.x+":"+this.y;
        }
    /*END~!Vector*/
    }
})();

三维贝塞尔方法:

var bezier=function(begin,c1,c2,end,t){
            var p=new SCD.Point(0,0)
            p.x=begin.x*(1-t)*(1-t)*(1-t)+c1.x*3*t*(1-t)*(1-t)+c2.x*3*t*t*(1-t)+end.x*t*t*t
            p.y=begin.y*(1-t)*(1-t)*(1-t)+c1.y*3*t*(1-t)*(1-t)+c2.y*3*t*t*(1-t)+end.y*t*t*t
            return p;
        }

最后一个参数是t,大小从0到1 ,0的时候是起点,1是终点.
附上一些方法:
包括: //判断两条线段是否相交 //检测点是否在多边形内//三维贝塞尔//二维贝塞尔//打碎三维贝塞尔 //打碎二维贝塞尔

(function(){
    SCD.util={
        //向量叉乘
        crossMul:function(v1,v2){
            return v1.x*v2.y-v1.y*v2.x;
        },
        //判断两条线段是否相交
        checkCross:function(p1,p2,p3,p4){
            var v1={
                x:p1.x-p3.x,
                y:p1.y-p3.y
            },
            v2={
                x:p2.x-p3.x,
                y:p2.y-p3.y
            },
            v3={
                x:p4.x-p3.x,
                y:p4.y-p3.y
            },
            v=this.crossMul(v1,v3)*this.crossMul(v2,v3)
            v1={
                x:p3.x-p1.x,
                y:p3.y-p1.y
            }
            v2={
                x:p4.x-p1.x,
                y:p4.y-p1.y
            }
            v3={
                x:p2.x-p1.x,
                y:p2.y-p1.y
            }
            return (v<=0&&this.crossMul(v1,v3)*this.crossMul(v2,v3)<=0)?true:false
        },
        //检测点是否在多边形内
        checkPP:function(point,polygon){
            var p1,p2,p3,p4
            p1=point
            p2={
                x:-100,
                y:point.y
            }
            var count=0
            //对每条边都和射线作对比
            for(var i=0;i<polygon.length-1;i++){
                p3=polygon[i]
                p4=polygon[i+1]
                if(this.checkCross(p1,p2,p3,p4)==true){
                    count++
                }
            }
            p3=polygon[polygon.length-1]
            p4=polygon[0]
            if(this.checkCross(p1,p2,p3,p4)==true){
                count++
            }
            //  console.log(count)
            return (count%2==0)?false:true
        },
        //  //  B(u) = P0 * ( 1 - u ) 2 + P1 * 2 * u ( 1 - u ) + P2 u2
            //P0 * ( 1 - u )3 + P1 * 3 * u * ( 1 - u )2 + P2 * 3 * u2 * ( 1 - u ) + P3 * u3
            //三维贝塞尔
        bezier:function(begin,c1,c2,end,t){
            var p=new SCD.Point(0,0)
            p.x=begin.x*(1-t)*(1-t)*(1-t)+c1.x*3*t*(1-t)*(1-t)+c2.x*3*t*t*(1-t)+end.x*t*t*t
            p.y=begin.y*(1-t)*(1-t)*(1-t)+c1.y*3*t*(1-t)*(1-t)+c2.y*3*t*t*(1-t)+end.y*t*t*t
            return p;
        },
        //二维贝塞尔
        quadratic:function(begin,c1,end,t){
            var p=new SCD.Point(0,0)
            p.x=begin.x*(1-t)*(1-t)+c1.x*2*t*(1-t)+end.x*t*t
            p.y=begin.y*(1-t)*(1-t)+c1.y*2*t*(1-t)+end.y*t*t
            return p;
        },
        //打碎三维贝塞尔
        brokenBezier:function(begin,c1,c2,end,partCount){
            var partCount=partCount||10;
            var points=[]
            var t=0;
            for(var t=0;t<=1;t+=1/partCount){

                points.push(this.bezier(begin,c1,c2,end,t));
            }
            return points;
        },
         //打碎二维贝塞尔
        brokenQuadratic:function(begin,c1,end,partCount){
            var partCount=partCount||10;
            var points=[]
            var t=0;
            for(var t=0;t<=1;t+=1/partCount){

                points.push(this.quadratic(begin,c1,end,t));
            }
            return points;
        }
    }
})();

No tags

判断点是否在贝塞尔曲线上的方法就是:
把贝塞尔曲线打碎成一个小段一小段的折线,然后去判断每一段折线有没有和点重合.
问题变成如何打碎贝塞尔曲线.
如果你看过我之前一篇文章的话,现在就知道这是多么有用了:
文章见:http://www.html-js.com/?p=1031# (用js计算三次贝塞尔曲线);
利用文中的方式,可以按需计算贝塞尔曲线.只需要调整时间t的增益就行.
看demo:
http://www.html-js.com/mj/pj/v2/test/testbezierBroken.html
调整滑块的值即可改变打碎程度(非ie下浏览)

No tags

判断点在圆弧上(顺时针画)

点为p.
圆弧圆心c0.半径r.起始弧度 a1,中止弧度 a2

先计算Math.abs(p.distance(c0)-r) 符合后.
计算p到c0的弧度 a0

此时如果a1不在第一和第二象限(很容易根据弧度得到),那么就把它逆时针旋转到0,a2和a0跟着旋转同样的角度.
如果a0和a2有超出2PI的,就减去2PI,例如a0=3PI,那就让它等于PI,总之将所有的弧度控制在0-2PI.
判断a0是不是>0&& 如果a1在第一和第二象限,那么就把它顺时针旋转到0,然后a2和a0跟着旋转同样的角度.
保持a2和a0在0-2PI内
判断a0是不是>0&&

我感觉这已经是一个比较简单的方法..

No tags

如何判断点在线段上(保留可变浮动范围)

线段又两个点 c0,c1表示,点用p表示.
直接计算p.distance(c0)+p.distance(c1)

0.1自己可以调节

No tags

OAuth2.0的refresh token

最近看人人网的OAuth认证,发现他是OAuth2.0,之前一直看的是新浪的OAuth,是OAuth1.0.

二者还是有很多不同的,主要的不同点在access token的获取方式.

OAuth1.0的access token获取过来之后,就可以存到数据库里,然后长期使用,因为它有效期很长,通常有效期是无限的.

但是OAuth2.0为了增强安全性,access token的有效期被大大缩短,通常只有几个小时,也可以申请增加到几十天,但是总是会有过期的时候.

为此,OAuth2.0增加了一个refresh token的概念,这个token并不能用于请求api.它是用来在access token过期后刷新access token的一个标记.

这里所描述的场景,通常是指那种长周期的应用.也就是需要一直保持用户在线的应用.

在线并不是说用户一直在用这个应用,也可能是用户已经离开,我们在后台仍然可以自动维持用户的状态.例如一个自动发状态的应用.用户并不需要操作这个应用,我们会定时在后台利用用户的accesskey帮助用户发送状态.这也算是用户维持登录状态的一种.

登录状态的维持,在OAuth中靠的是access token,只要我们的应用定时从数据库里取出用户的access token,然后利用access token就可以使用这个用户的身份去请求api了.

在OAuth1.0中用户的登录状态是一直存在的.

在OAuth2.0中用户的登录状态需要通过不断刷新来维持.

例如上面提到的应用.假设更详细的场景,这个应用在用户授权之后,每天给用户的人人网发送一条状态报告当天的日期.

用户授权之后,获取到一个access token和一个refresh token,还有一个是session key,这个是国内大多数开放平台自己添加的一个标记,可以让用户使用http来调用api,如果没有它,用户只能通过https来调用api.session key的生命周期和access token是相同的.

我们把这三个值存到一个队列的数据库中.

然后,在每天的10点,我们遍历这个数据库表,取出它的access token和session key,然后用他们去请求api,如果发现他们已经过期,我们就需要利用refresh token去重新刷新,获取新的access token和session key.然后利用他们去请求api,如果请求的时候提示refresh token也已经过期,那么这时候用户的登录状态就会过期,这说明这个用户至少2各月没有在此应用活跃了,这个活跃不光指用户自己在使用应用,也包括应用自动调用用户api的行为.

每次刷新token的时候都会返回一个新的refresh token,所以说如果你的应用每个月帮用户发一条状态的话,走上面的流程,一直下去,这个用户的登录状态一直都不会过期,至于为什么,自己去琢磨哦,琢磨透了也就理解了.

 

No tags

简单的bannerMaker和几个零碎偏僻的知识点

这几天做一个bannermaker.遇到不少问题.总结一下吧:

先试用一下….可能会有问题…有问题及时反馈哦,亲
后台版bannermaker: http://www.html-js.com/bannerMaker-tmall/index.php
HTML5版bannermaker: http://www.html-js.com/bannerMaker-tmall/index_1.php

两个版本的bannermaker,主要是一开始用php处理图片的,后来发现php在图片上写字只能用一种字体,宋体的英文很丑,这个方案直接废掉了.
第二个版本是用html5的canvas来处理图像的,最后传给服务器,用php压缩成png-8,然后输出到浏览器让用户下载.

几个点:
1. 经试验,demo的php环境支持GD库,也支持读写文件系统,但是很可惜不支持使用ttf字体来作图.
2. 用php画宋体的粗体没有普遍方法,可以先画一次,然后右移一个像素再画一次,最后出来的就是粗体.
3. 用php生成png-8的方法:

ImageTrueColorToPalette($image, false, 255);

4. 使用GD库的时候会有乱码,网上的解决方案大部分不起作用,有这样一个方法,用此方法转换后的utf-8字符就可以作为ImageTTFText的参数使用了:

function to_entities($string) {
    $len = strlen($string);
    $buf = "";
    for ($i = 0; $i < $len; $i++) {
        if (ord($string[$i]) <= 127) {
            $buf .= $string[$i];
        } else if (ord($string[$i]) < 192) {
            //unexpected 2nd, 3rd or 4th byte
            $buf .= "�";
        } else if (ord($string[$i]) < 224) {
            //first byte of 2-byte seq
            $buf .= sprintf("&#%d;",
                            ((ord($string[$i + 0]) & 31) << 6) +
                            (ord($string[$i + 1]) & 63)
            );
            $i += 1;
        } else if (ord($string[$i]) < 240) {
            //first byte of 3-byte seq
            $buf .= sprintf("&#%d;",
                            ((ord($string[$i + 0]) & 15) << 12) +
                            ((ord($string[$i + 1]) & 63) << 6) +
                            (ord($string[$i + 2]) & 63)
            );
            $i += 2;
        } else {
            //first byte of 4-byte seq
            $buf .= sprintf("&#%d;",
                            ((ord($string[$i + 0]) & 7) << 18) +
                            ((ord($string[$i + 1]) & 63) << 12) +
                            ((ord($string[$i + 2]) & 63) << 6) +
                            (ord($string[$i + 3]) & 63)
            );
            $i += 3;
        }
    }
    return $buf;
}
ImageTTFText($tim, 10.2, 0, 10, 123, $white, "simsun.ttf", to_entities($_POST['title']));

5. 用pathinfo可以方便获取文件名信息: http://www.w3school.com.cn/php/func_filesystem_pathinfo.asp
6. 自动调用浏览器的下载下载文件:

$filepath = "temp/" . time() . md5($src) . ".png";
    imagepng($tim, $filepath);
    header("Content-type:image/png");
    header("Content-Disposition: attachment; filename=$filepath");
    header('Content-Length: ' . filesize($filepath));
    $fp = fopen($filepath, 'rb');
    fpassthru($fp);
fclose($fp);

7. 怎么用html5处理图片然后传给后台继续处理?

用html5的canvas处理图片,然后用canvas的toDataURL() [ 文档 ] 方法将canvas的内容变成一张图片,形式是dataurl的字符串,然后post到后台,后台吧dataurl当成普通url处理即可获取到图片资源:

$im = imagecreatefrompng($src);//$src就是一个dataurl

等等等等….

No tags

将dom结构缓存到本地存储里有没有必要和意义?

将dom结构缓存到本地存储里有没有必要和意义?
是一个静态页面,内容变化不是很频繁,页面分成N个独立模块,每个模块由不同的人维护.
将这些内容缓存到本地存储,然后利用时间戳机制,只有时间戳过期的时候才会去服务器更新.
所有的模块的更新只使用一个http请求,也就是说只会比平常多出一个http请求并不是每个模块独立去更新.

之所以开始怀疑这样做的意义.
因为:
1.前提是你的网站不需要考虑搜索引擎,例如淘宝网.
2.会多出1-几个请求...你可以将请求控制在1个之内,影响不是很大.
3.因为只使用一个请求,得到内容后,需要正则匹配将内容分解到每个模块中,可能会耗费一些浏览器性能,经过测试不会出现明显的性能问题.
4.维护和配置麻烦...学习成本高.....
5.浏览器本身就有缓存,包括对整个页面的缓存.只是这样做,刷新的时候也不会去服务器获取内容.

大家怎么认为呢,希望共同探讨下

No tags

之前文章中生成的小色盘,有白色斑点,因为算法原因,没有顾及每个像素.这个算法是由模型推导像素点的,所以有瑕疵.改进一下即可,我们由像素点推导模型:

  for(var y=0;y<400;y++){
        for(var x=0;x<400;x++){
            var r=Math.sqrt((x-200)*(x-200)+(y-200)*(y-200))
            if(r<200){
                var angle=(Math.atan2((200-y),(200-x)))*180/Math.PI
                angle<0&&(angle+=360);
                pixel=HSVToRGB(angle,r/200,0.8)
                setData(imageData2,x,y,[
                    pixel.r,
                    pixel.g,
                    pixel.b,
                    255
                ]);
            }
        }
    }

点击颜色,页面背景色将会变化


No tags

Older posts >>

调试ing
ip:38.107.179.231refer:time:2012-01-27 18:58:13url:http://www.html-js.com/index.php