Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

JavaScript 相册/照片墙 算法

  照片墙效果貌似现在所有的相册都在用,很流行的。看上去效果也不错,在一行中的每一个图片都是等高的,不会参差不齐。其实仔细看你会发现每一行不一定是等高的。也就是说,这个效果是用整行的高度去调整图片的宽度,等比例缩放。而图片之间的间隔是不变的。
  我的思路是,从第一个张图片开始遍历图片。遍历到图片的时候,先把它等比例缩放到高度为一个特定的高度ROWHEIGHT,也就是让所有图片的高度统一下来,宽度根据高度的缩放比例来缩放,然后把宽度累加起来(包括margin)。直到宽度超出容器的宽度时候,这样,我们就有了一行的数据。这时候我们要判断,是否应该就把超出的部分在每张图片中等比缩小回去,还是去掉这行的最后一张图片之后把每这行张图片等比放大。我们可以判断这两个状态哪个更接近满行就用哪个。这个操作,我们还需要记录这一行与满行的差,这个数据在计算图片需要缩放多少时候会用到。得到一行的数据之后,我们就要去计算超出的部分在高度中应该调整多少。我们可以把图片看作是一个高度为自变量,宽度为因变量的函数。这样我们只要把这一整行的所有图片的导数相加就可以得到整行的导数了。然后把上面记录的行与满行的差除以这个数字就可以得到高度需要变化的量了。之后,只需要在ROWHEIGHT中修正这个变化量,再计算等比缩放的宽度就可以得到图片最终的显示宽度了。
  由于我没有太多的图片来测试,所以我的示例中只是用了SPAN元素来替代图片。数据是PHP生成的,我就不贴代码了,不过我会在最后的部分留下这个例子的下载链接,里面用的是PHP生成好的数据。
  下面是代码部分,如果我的描述中有哪里模糊的,在代码中应该可以看明白。 <!DOCTYPE html>
<style>
#panel {
  width:960px;margin:0px auto;
  border:1px solid #CCC;
  font-size:0px;
}
#panel span {
  display:inline-block;
  background:#E8E8E8;margin:10px;
  text-align:center;
  font-size:14px;
}
</style>
<div id="panel"></div>
<script>
//常量声明
var WIDTH=960,  //容器宽度
    ROWHEIGHT=100,  //默认图片行的高度
    MARGIN=20;  //图片之间的margin

//JSONP回调函数
//图片分行
function LoadedData(e){
  var i,o,w,h,sh,sw,c,lc,l,s;
  i=0,s=[],c=0;
  //遍历数据
  while(o=e[i++]){
    //获取宽度和高度
    w=o[0],h=o[1];
    //把高度设置成默认的行高
    //并且把宽度等比例压缩
    sh=ROWHEIGHT;
    sw=sh/h*w;
    //保存上一次的宽度统计
    lc=c;
    //统计元素的宽度
    c+=sw+MARGIN;
    //判断宽度是否超出容器
    if(c>=WIDTH){//宽度超出或等于容器宽度
      //判断是补一个元素还是去掉一个元素
      if(c-WIDTH<WIDTH-lc){
        //补一个元素
        s.push([w,h]);
        //计算这行并输出
        makeRow(s,c-WIDTH);
        //清空统计
        s=[],c=0;
      }else{
        //去掉一个元素
        //计算这行并输出
        makeRow(s,lc-WIDTH);
        //清空统计并记录当前元素
        s=[[w,h]],c=sw+MARGIN;
      };
    }else s.push([w,h]);//宽度不足,继续循环
  };
  //如果最后还有不满行的数据则正常数据
  if(c)makeRow(s,0);
};

//计算一行中图片的尺寸
function makeRow(s,c){
  var ds,i,o,w,h,sw,sh;
  ds=0,i=0;
  //计算图片的导数总和
  //ds是高度每变化1时宽度的变化量
  while(o=s[i++])ds+=o[0]/o[1];
  //计算新的行高
  sh=ROWHEIGHT-c/ds;
  //遍历计算结果,并创建相应元素
  i=0;
  while(o=s[i++]){
    w=o[0],h=o[1];//获取尺寸
    sw=sh/h*w|0;//缩放
    putPicture(sw,sh,w,h);//输出
  };
};

//创建元素
function putPicture(sw,sh,w,h){
  var o=document.createElement("span");
  o.style.width=sw+"px";
  o.style.height=sh+"px";
  o.style.lineHeight=sh+"px";
  o.innerHTML="("+w+","+h+")";
  panel.appendChild(o);
};

var panel;
window.onload=function(){
  //获取元素
  panel=document.getElementById("panel");
  //创建script载入数据
  var script;
  script=document.createElement("script");
  script.src="http://127.0.0.1/test.php?callback=LoadedData";
  document.body.appendChild(script);
};
</script>


JavaScript相册照片墙算法
网名:
54.144.24.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^