跳到主要内容

构建一个视差滚动讲故事的框架

  • 所需知识:中级JavaScript,扎实的Photoshop词汇
  • 要求:Photoshop,jQuery,jQuery ScrollTo插件,jQuery Easing插件
  • 项目时间:大概在半小时到几个月之间
  • 支持文件

MS Paint Adventures我有一种顿悟:在这个时代,没有理由将漫画保持在20世纪早期胶版印刷的限制之内。不需要墨水线条艺术,或与艺术竞争页面空间的手写字母泡沫,无需将图纸打包成固定尺寸的网格并以四倍的倍数打印:这些都是我们不再解决问题的方法有。所以,我接受了斯科特麦克劳德的无限画布通过将一些JavaScript扔进锅中来提高赌注。结果是哈梅林的Hobo Lobo,一个关于一个城市,它的顾忌,一些老鼠,一个洛沃,他的木管乐器和倒下的东西的网络时间故事。

我想教你制作一个自己的视差器,向你展示一种为它绘制资产的方法,并最终激励你在自己的方向上开拓互联网讲故事的前沿。

01.视差器的诞生

作为伪造3D空间的手段的视差是非常违反直觉的。当你用一个简单的50mm相机镜头环顾四周时,你会发现随着物体距离的增加,更大的东西可以适合你的视野。大约半米,你可以看到一本完整的书。在大约三米处,您可以看到整个沙发。从20米开始,您可以看到整栋房子。很简单的东西。

然而,视差不涉及距离。它涉及向量。如果你从上一个例子中查看你的相机,并将一米走到一边,那么这本书将完全离开你的视口,你会看到大约三分之二的沙发,房子几乎不会移动。这种东西在数学上描述起来非常困惑。

为了更好地设想巨大的全景应该如何表现,让我们将舞台和所有视差层分成面板。这解决了我们还不知道的很多问题。首先,我们不必使用难以完全掌握的单一全景图,而是可以分段绘制故事,更好地预测图层在视图内,在浏览器中心内和附近时的相互作用窗口(如下虚线所示)。

页面应该加载第一个面板的所有层彼此居中并且窗口的中心。当一个向右滚动时,图层将在面板之间的边界处对齐,然后再次在第二个面板上居中。俯视一系列走廊的感觉。

该图显示了视差空间的另一个违反直觉的方面。最远的层,即应该从相机示例中适合房屋的层,水平地是所有层中最窄的层(垂直地,该层将与其余层一样高,为了易读性目的,该图显示它们更短)。为了绘制一个像我们可以放在最近层的最大书本一样大的房子,我们必须溢出到最远层的相邻面板。

在Flash中伪造全景视差会相对微不足道,但Flash并不像过去那样性感。另外,完整的叙述对于更新来说会很麻烦,并且不像我希望的那样有利于好奇的访问者进行逆向工程。

让我们为适合此图的Parallaxer设置一个小支架。我将使用XHTML,因为HTML5提供的任何内容都没有隐含的需要,但您可以使用任何doctype转向您。我们来包括JQuery 1.6.2(在撰写本文时我们可以获得最新鲜的),JQuery ScrollTo 1.4.2(暂时没有更新,但仍然是一个很棒的插件,A +++会再次插入),以及JQuery Easing 1.3(另一个老人,但好东西)。




1A

2A

3A

4A

5A

6A



1B

2B

3B

4B

5B

6B



1C

2C

3C

4C

5C

6C



1D

2D

3D

4D

5D

6D



1E

2E

3E

4E

5E

6E



我们将在这里使用五层,理论上认为Parallaxer对它可以支持的层数没有任何限制。 A层位于后面,而E层位于前面。溢流控制是必要的,以预测在舞台最右侧发生的不稳定行为;如果没有它,我们将滚动最后一个面板超过其垂直对齐轴。数字和字母分别代表面板和图层,这里只是作为帮助者。

我们需要决定哪一层是静态的,哪一层是视差的反对。该层也将是叙述容器的父级。

我们还需要为静态图层中的面板选择宽度,并为其他图层选择比率:面板宽度相对于静态图层。我将选择B层作为我的主要部分,选择400px作为其宽度。让剩下的图层面板的比例分别为0.75,1.25,1.5和1.75,分别达到300,500,600和700像素。这些是Hobo Lobo的尺寸。我发现它们足够灵活,适用于各种各样的空间情况,但它们完全取决于你。





1A

2A

3A

4A

5A

6A



1B

培根ipsum dolor坐在amet anim生涩的牛腩,牛腩salami cillum下巴。


2B

Laboris occaecat ut dolore minim,非shankle laborum香肠boudin肉丸肩。


3B

Pastrami shankle ad chuck,鸡肉条牛排pariatur culpa ex fatback sunt incididunt exercit elit。


4B

Elit dolor labore in pork tempor tri-tip cillum tenderloin duis,eiusmod ut aliquip strip steak。


5B

Pancetta猪在dolore id laborum,cupidatat adipisicing mollit。


6B

Officia incididunt adipisicing pancetta,ut veniam排骨cillum tempor sidenk chuck ex consectetur。




1C

2C

3C

4C

5C

6C



1D

2D

3D

4D

5D

6D



1E

2E

3E

4E

5E

6E



请注意图层B面板中的叙述div和带有与图层B中的ID对应的面板的链接的菜单。这些将提供另一种滚动方法。

@charset“UTF-8”;

/ * GENERAL和CLEANUP * /
* {margin:0px;填充:0px; }
img {border:0px; vertical-align:bottom; }
body {background-color:#fff; font-size:14px; font-family:Monaco,Courier,monospace; }

/ * PARALLAXER * /
ul#panelControl {position:fixed;上:13px;左:70px; z-index:999; }
ul#panelControl li {float:left;显示:块; padding-right:3px; }
ul#panelControl li a {display:block; border-radius:20px;背景色:#000;颜色:#fff;宽度:26px;身高:26px; text-align:center; font-size:20px; line-height:22px; text-decoration:none;}
ul#panelControl li a.clicked {opacity:0.3;滤波器:α(不透明度= 30); }
ul#panelControl li a:hover {text-decoration:none;不透明度:1;滤波器:α(不透明度为100); background-color:#fff;颜色:#000; box-shadow:0px 5px 5px#000; }
ul#panelControl li a span {display:block; padding-top:2px; }

#overflowControl {overflow:hidden;位置:相对;身高:620px;上:90px; }
#layerSling {}
#layerSling> div {display:block;位置:绝对;顶部:0px;左:0; }

#layerSling .p {身高:400px;向左飘浮;位置:相对;溢出:可见; text-align:center; }
#layerSling .p img {display:block;位置:绝对;顶部:0;左:0; }
#layerB .p {width:400px; }
#layerB .p .narrative {position:absolute;上:400px;左:0;宽度:360px;填充:20px; text-align:left; }

/ * FLAIR * /
#layerA .p {box-shadow:inset 5px -50px 40px rgba(218,74,141,0.9);颜色:#942a5c; }
#layerB .p {box-shadow:inset 5px -40px 40px rgba(187,135,197,0.9);颜色:#86578f; }
#layerC .p {box-shadow:inset 5px -30px 40px rgba(165,166,216,0.9);颜色:#696aae; }
#layerD .p {box-shadow:inset 5px -20px 40px rgba(154,206,241,0.9);颜色:#4ca1d9; }
#layerE .p {box-shadow:inset 5px -10px 40px rgba(153,227,255,0.9);颜色:#3dc3f5; }

我们将开始溢出控制,没有溢出,高度,并把它放在窗口顶部一点点。现在,我将在JavaScript中定义所有面板的宽度。最后,当我们完成实验时,我们应该在CSS中烘焙一些东西,并让其他人计算出服务器端并烘焙到样式标签中以回收丢失的性能。在我们开发过程中,标有“天赋”的风格只是一个临时的支架。

所有这些设置,我们需要JavaScript来做一些事情:

  • 我们需要视差来实现视差。
  • 我们需要所有面板始终在窗口中间对齐。
  • 在面板边缘与所有层重叠的位置,我们应该关闭外出面板的叙述并展开其中的内容。
  • 同时我们应该改变面板控制按钮的样式,以提供关于访问过哪些面板的视觉提示。
  • 我们需要面板控制按钮来平滑地制作动画,而不是跳转到给定的面板。

Function AParallax(){
Var P = This;
P.panelWd = 400; //主面板的宽度
p.otherLayers = [{id:'layerA',比率:0.75},{id:'layerC',比率:1.25},{id:'layerD',比率:1.5},{id:'layerE',比率: 1.75}]; //所有其他面板
p.panelCount = $('#layerB .p')。length; //面板总数

P.didScroll = False;
P.panelHovered = 0; //当前面板正在盘旋;脚本开始触发后会立即更改

p.overflowControl = $('#overflowControl'); //我们将处理这个足以保证将其放入自己的var中

//所有方法都将在这里以及构造函数代码

$(窗口).resize(函数(){
//这里我们将添加调整窗口大小时需要触发的所有内容
});

$(窗口).scroll(函数(){
P.didScroll = True;
});

SetInterval(function(){
If(p.didScroll){
P.didScroll = False;
//所有受滚动影响的事情都会在这里执行
}
},30);
}

$(文件)。就绪(函数(){
//在所有代码加载时执行
P = New AParallax();
});

该类将包含所有变量和方法,以便不会以奇怪的名称污染全局范围。大多数功能都是方法AParallax类。为了简化代码,我们正在定义P解决这个在类中,然后命名工作视差对象P,因此在没有类的情况下从内部和内部调用方法和变量看起来是一样的。

我们还为我们需要做出反应的事件设置了几个领域。请注意的setInterval每30毫秒触发一次并连接到scroll事件的函数。不同的浏览器触发了$(窗口).scroll()事件不同,并且在滚动的每个像素上执行大量代码会使事情陷入困境。该间隔通过仅允许每30毫秒进行一次滚动重新计算来减轻这种情况。

让我们设定基本方法:

This.crunchWinVars = Function(){
p.winWd = $(window).width();
p.winHoriSp2Panel = Math.floor((p.winWd - p.panelWd)/ 2);
$('#layerSling')。offset({left:p.winHoriSp2Panel});
p.overflowControl.width(p.winWd +(p.panelCount-1)* p.panelWd);
};

This.init = Function(){
$('#layerB')。width(p.panelCount * p.panelWd); //这可能会更好地烘焙到服务器样式标签
for(var ih = 0; ih p.otherLayers [ih] .ref = $('#'+ p.otherLayers [ih] .id); //我们将大量引用这些内容
$(p.otherLayers [ih] .ref).width(Math.ceil(p.panelCount * p.panelWd * p.otherLayers [ih] .ratio)); //这可能会更好地烘焙到服务器样式标签
$('#'+ p.otherLayers [ih] .id +'。p')。width(Math.round(p.panelWd * p.otherLayers [ih] .ratio)); //这可能会更好地融入css
$('#'+ p.otherLayers [ih] .id +'。p')。text(Math.round(p.panelWd * p.otherLayers [ih] .ratio)); //帮手线
p.parallax(p.otherLayers [ih] .ref,p.otherLayers [ih] .ratio);
}
};

this.parallax = function(containerRef,ratio){
containerRef.css({left:(1 - ratio)*(p.panelWd / 2 + $(window).scrollLeft())+'px'});
}

P.crunchWinVars();
压住他();

第一种方法处理与浏览器窗口相关的数字,然后使阶段居中并将准确的宽度应用于溢出控件。如果我们的视差只是一个单独的面板是一个悲伤的视差,溢出的宽度将只是屏幕宽度。没有滚动,Parallaxer实际上不会做任何事情。我们需要增加每个额外静态面板的宽度。

第二种方法启动视差并设置不同层的面板宽度以及层本身的总宽度。由于面板都是左侧浮动,我们不能给它们包装的机会。它也是第一次调用视差函数。

最后,视差。我通过非常低效的试错方法达到了这个等式。我会永远感激谁能够找到一个适当的数学证明,为什么这个方程有效,所以对此有所了解。

一旦我们将下面的代码插入到setInterval循环中,我们就会设置一个功能Parallaxer。

for(var ih = 0; ih p.parallax(p.otherLayers [ih] .ref,p.otherLayers [ih] .ratio);
}

当我们滚动面板时,确定何时展开叙述的功能是aParallax类之外的唯一功能。我们将在文档的头部定义它。

Function PanelEventSniffer(){
var scroll = $(window).scrollLeft();

if(scroll> = -200 && scroll <200 && p.panelHovered!= 1){
P.panelNarr( '#C_1');
P.panelHovered = 1;
}
否则如果(滚动> = 200 &&滚动<600 && p.panelHovered!= 2){
P.panelNarr( '#C_2');
P.panelHovered = 2;
}
否则如果(滚动> = 600 &&滚动<1000 && p.panelHovered!= 3){
P.panelNarr( '#C_3');
P.panelHovered = 3;
}
else if(scroll> = 1000 && scroll <1400 && p.panelHovered!= 4){
P.panelNarr( '#C_4');
P.panelHovered = 4;
}
否则如果(滚动> = 1400 &&滚动<1800 && p.panelHovered!= 5){
P.panelNarr( '#C_5');
P.panelHovered = 5;
}
否则如果(滚动> = 1800 &&滚动<2200 && p.panelHovered!= 6){
P.panelNarr( '#C_6');
P.panelHovered = 6;
}
}

在Hobo Lobo上,我生成了这个有条件的服务器端。如果这完全是在JavaScript中完成的,那么更新会更加麻烦并且不那么有用。这样做可以让我们在每个面板上运行任意代码,而不是JavaScript的其余部分,这些代码可以放在自己的文件中,只下载一次。条件开始于-200px(浏览器窗口外不可能的一半静态面板),以保持整洁和线性与所有后续值。

this.panelNarr = function(aPanel){
var elevator = $('#panelControl a [href =“'+ aPanel +'”]');
var narrative = $(aPanel +'.narrative');
var overflowNewHt = narrative.outerHeight()+ 500;

$( '故事:可见')停止(真,真).slideUp(100); //汇总其他幻灯片的文本(如果有任何展开)
if(!elevator.hasClass('clicked')){
Elevator.addClass( '点击'); //将单击的类添加到我们刚刚传递的页面的panelControl中
}
if(overflowNewHt> p.overflowControl.outerHeight()){
p.overflowControl.animate({'height':overflowNewHt},200,'easeInOutSine');
}
Narrative.slideDown(500); //展开叙事

if(p.winWd!= $(window).width()){
P.crunchWinVars(); //有时扩展溢出会添加垂直滚动条,因此我们需要考虑到这一点
}
};

This.panelControl = Function(){
$('#panelControl a')。click(function(elevator){
Elevator.preventDefault();
p.correctScroll($(本).attr( 'href' 属性));
});
}

this.correctScroll = function(hash,duration){
If(duration === Undefined){
Var Duration = 8345;
}
If($(window).scrollTop()){
//如果我们在一行中排队x&y,则scrollTo将永远向上滚动,因此单独执行它可以让我们有一个brisker upscroll和一个更长的一个
$ .scrollTo(hash,{'axis':'y','queue':true,'duration':Math.floor($(window).scrollTop()* 3/2 + 200),'offset':{ 'top': - 90}});
}
$ .scrollTo(hash,{'axis':'x','queue':true,'duration':duration,'offset':{'left': - p.winHoriSp2Panel},'easing':'easeInOutSine'} );
}

P.panelControl();

其余的方法是不言自明的。第一个展开叙述,并进行与展开相关的清理工作。第二个绑定平滑的动画CorrectScroll功能到面板控件。第三个动画滚动动画,独立完成两个轴,以便快速进行y滚动,x滚动可以从悠闲的缓和中获益。

最后,确保CrunchWinVars()$(窗口).resize()并运行PanelEventSniffer()SetInverval()。现在你手上有最可想象的骨骼可见视差。万岁!去吧!

还有一些事情可以改进。就像在视觉上,Parallaxer在移动浏览器上也是如此;我还没有探索劫持触摸事件和手势来让iOS在合适的时间计算偏移量。我可能会尝试不使用scrollTo插件;使用它是一个早期开发节省时间的决定。此外,应该有一种更优雅的方式让用户中断CorrectScroll虽然它是动画。等等。改进的空间是无限的。

我不想添加的一些东西,比如加载屏幕。我喜欢牵线木偶剧院的感觉。如果你知道要寻找什么,你可以看到字符串,椽子里的人和忍者在行为之间移动家具。留下一些粗糙度可以带来更温暖的体验。艺术家的邋hand手总是很有趣。

02.一种PNG铅笔画的方法

现在开始使用Photoshop!我使用CS3是因为我有一台PowerPC,并且被所有开发者所遗弃。调整系统下方的键盘快捷键。

使用包含每个视差图层的五个智能对象设置主文档,并构建一个动作以生成拨入面板的图层组合,例如Parallaxer的面板控件。

我在4英寸的纸条上绘制艺术品,使用灯箱进行登记。

我以400 Dpi扫描它并将其清理一点,然后将其放入指定的智能对象中。在绘画时,我通常会使用鲜明的对比色来代替我的绘画。这是一个老鼠画,大小和适当的位置后调整了一些水平和一些纸屑躲过。

将焦点放在绘图图层上,选择全部并复制到剪贴板,然后取消选择并创建纯色图层。

按住Alt并单击颜色图层蒙版。文件应该是白色的,我们现在只看到面具。将绘图粘贴到蒙版中,然后使用反斜杠(\)键退出视图。单击选项+ I以反转蒙版。这就是我们所看到的:

在其他单色图层上使用平板电脑绘制填充和高光。

关闭狂热的火烈鸟层,切片,保存为网络24位PNG和优化

你有它。您现在是经过认证的Parallaxeer。祝好运!

StevanŽivadinović曾经出生在一个虚构的国家,但后来变得更好了。他获得了认可机构的认证,可以从事艺术创作。检查他虚无主义的金丝雀哈梅林的Hobo Lobo



翻译字数超限