我正在尝试实现图像的展开效果,并且在我的一位在线朋友的帮助下,我已经达到了效果。
//Size of image
var _w = 920;
var _h = 452;
//Fold instance
var _foldA;
//First we load an image to use:
var _img = new Image();
_img.onload = loaded;
_img.src = "http://tecnoweb.bottlementors.com/images/tecno-camon.jpg";
function loaded(e) {
//Init the fold image
_foldA = new FoldImage(document.getElementsByClassName("camon-mobile")[0], _w, _h, 4, 3, 3);
_foldB = new FoldImage(document.getElementsByClassName("camon-sky")[0], _w, _h, 4, 3, 3); //Play around with this, especially last parameter
_foldA.animIn(); //you can execute this on scroll or with a delay
}
//Class for applying the effect
function FoldImage(_me, _w, _h, _tilesX, _tilesY, _startTileID) {
var _this = this;
_me.style.width = _w + "px", _me.style.height = _h + "px";
//Create canvas tiles
var _numTiles = _tilesX * _tilesY;
var _tiles = [];
var _tileW = Math.round(_w / _tilesX),
_tileH = Math.round(_h / _tilesY);
var _animedIn = false;
for (var i = 0; i < _numTiles; i++) _tiles.push(new FoldTile(i, _me, _tileW, _tileH, _tilesX, _tilesY));
//Draw on all canvasses
for (i = 0; i < _numTiles; i++) _tiles[i].drawSection(_img, _tileW, _tileH);
_this.animIn = function() {
if (_animedIn) return;
_animedIn = true;
for (i = 0; i < _numTiles; i++) _tiles[i].animIn(.4, _startTileID);
}
_this.rerun = function() {
_animedIn = false;
for (i = 0; i < _numTiles; i++) _tiles[i].reset();
_this.animIn();
}
//This works like a linked list, each cell dispatch an event to trigger the animation for a neighbour
_me.addEventListener("tileAnim", neighbourCall);
var _totalCalls = 0;
function neighbourCall(e) {
_totalCalls++;
for (i = 0; i < _numTiles; i++) _tiles[i].neighbourCalledMe(e.detail, _totalCalls);
}
}
function FoldTile(_id, _container, _tileW, _tileH, _tilesX, _tilesY) {
var _this = this;
var _me = document.createElement("div");
_me.className = "tile";
var _canvas = document.createElement("canvas");
_canvas.className = "canvas";
var _x = (_id % _tilesX) * _tileW,
_y = Math.floor(_id / _tilesX) * _tileH;
var _shade = document.createElement("div");
_shade.className = "shade";
_me.appendChild(_canvas);
var _scale = 1; //To-do: adjust for retina screens
var _oriTileW = _tileW,
_oriTileH = _tileH;
var _maxRotX = 90,
_maxRotY = 90,
_numTiles = _tilesX * _tilesY;
var _rotX = 0,
_rotY = 0;
var _origin = "0 50%",
_perspective = 500;
var _oriX = "0",
_oriY = "0";
var _ctx = _canvas.getContext('2d');
_this.drawSection = function(_img, _tileW, _tileH) {
_canvas.width = _tileW * _scale, _canvas.height = _tileH * _scale;
var _x = (_id % _tilesX) * _tileW,
_y = Math.floor(_id / _tilesX) * _tileH;
_me.style.left = _x + "px", _me.style.top = _y + "px", _me.style.width = _tileW + "px", _me.style.height = _tileH + "px";
_ctx.drawImage(_img, (_id % _tilesX) * _oriTileW, Math.floor(_id / _tilesX) * _oriTileH, _oriTileW, _oriTileH, 0, 0, _tileW * _scale, _tileH * _scale);
_container.appendChild(_me);
}
var _animTime = 0;
var _animInCalled = false;
_this.animIn = function(_time, _startTileID) {
_animTime = _time;
if (_id == _startTileID) {
_animInCalled = true;
started();
return;
}
//Find out the first neighbour tiles:
var _xstart = (_startTileID % _tilesX) * _tileW + _tileW * .5,
_ystart = Math.floor(_startTileID / _tilesX) * _tileH + _tileH * .5;
var _mycenterX = _x + _tileW * .5,
_mycenterY = _y + _tileH * .5;
var _distanceToStartTile = Math.sqrt(Math.pow((_mycenterX - _xstart), 2) + Math.pow((_mycenterY - _ystart), 2));
if (_distanceToStartTile < (Math.max(_tileW, _tileH) + 2)) _this.neighbourCalledMe(_startTileID, 0);
}
_this.reset = function() {
_me.style.visibility = "hidden";
_animInCalled = false;
_rotX = 0, _rotY = 0;
_animTime = 0;
TweenLite.set(_shade, {
autoAlpha: 1
});
}
//Neighbour finished animIn and is now calling this to start
_this.neighbourCalledMe = function(_neighbourId, _totalCalls) {
if (_animInCalled) return;
//Find distance and relative position:
var _xstart = (_neighbourId % _tilesX) * _tileW + _tileW * .5,
_ystart = Math.floor(_neighbourId / _tilesX) * _tileH + _tileH * .5;
var _mycenterX = _x + _tileW * .5,
_mycenterY = _y + _tileH * .5;
var _distanceToStartTile = Math.sqrt(Math.pow((_mycenterX - _xstart), 2) + Math.pow((_mycenterY - _ystart), 2));
//Cancel if too far away:
if (_distanceToStartTile > (Math.max(_tileW, _tileH) + 4)) return;
_animInCalled = true;
//Find the axis to rotate around
if (_mycenterX < _xstart) _rotY = _maxRotY, _oriX = "100%";
else if (_mycenterX > _xstart) _rotY = -_maxRotY, _oriX = "0";
else _oriX = "50%";
if (_mycenterY < _ystart) _rotX = -_maxRotX, _oriY = "100%";
else if (_mycenterY > _ystart) _rotX = _maxRotX, _oriY = "0";
else _oriY = "50%";
//Set origin
_origin = _oriX + " " + _oriY;
//Set initial position
TweenLite.set(_me, {
rotationX: _rotX,
rotationY: _rotY,
transformPerspective: _perspective,
transformOrigin: _origin
});
//Anim in
var _myTime = _animTime + Math.random() * .3,
_ease = Quad.easeOut;
if (_totalCalls > _numTiles * .5) _ease = Back.easeOut, _myTime += .2;
//Call neighbours when almost there:
setTimeout(callNeighbour, Math.max(0, _myTime * 1000 * .5));
_me.appendChild(_shade);
TweenLite.to(_me, _myTime, {
rotationX: 0,
rotationY: 0,
transformOrigin: _origin,
transformPerspective: _perspective,
ease: _ease,
onStart: started,
onComplete: animInOver
});
TweenLite.to(_shade, _myTime * .9, {
autoAlpha: 0,
ease: Quad.easeOut
});
}
function started() {
_me.style.visibility = "visible";
}
function callNeighbour() {
_container.dispatchEvent(CPCustomEvent("tileAnim", _id));
}
function animInOver() {
if (_id % _tilesX == 0 || _id % _tilesX == (_tilesX - 1) || Math.floor(_id / _tilesY) == 0 || Math.floor(_id / _tilesX) == (_tilesY - 1)) {
if (_id % _tilesX == 0) _rotY = _maxRotY, _oriX = "100%";
else if (_id % _tilesX == (_tilesX - 1)) _rotY = -_maxRotY, _oriX = "0";
else _rotY = 0, _oriX = "50%";
if (Math.floor(_id / _tilesY) == 0) _rotX = -_maxRotX, _oriY = "100%";
else if (Math.floor(_id / _tilesX) == (_tilesY - 1)) _rotX = _maxRotX, _oriY = "0";
else _rotX = 0, _oriY = "50%";
//Set origin
_origin = _oriX + " " + _oriY;
_me.addEventListener("mouseenter", over);
_me.addEventListener("mouseleave", out);
_me.addEventListener("mousedown", clicked);
_me.addEventListener("touchstart", clicked);
}
}
function over(e) {
TweenLite.to(_me, .3, {
rotationX: -_rotX * .1 * (Math.random() * .5 + .5),
rotationY: -_rotY * .1 * (Math.random() * .5 + .5),
transformOrigin: _origin,
transformPerspective: _perspective,
ease: Quad.easeOut
});
TweenLite.to(_shade, .3, {
autoAlpha: .05,
ease: Quad.easeOut
});
}
function out(e) {
TweenLite.to(_me, .3, {
rotationX: 0,
rotationY: 0,
transformOrigin: _origin,
transformPerspective: _perspective,
ease: Quad.easeOut
});
TweenLite.to(_shade, .3, {
autoAlpha: 0,
ease: Quad.easeOut
});
}
function clicked(e) {
e.stopPropagation();
TweenLite.to(_me, .1, {
rotationX: -_rotX * .2 * (Math.random() * .5 + .5),
rotationY: -_rotY * .2 * (Math.random() * .5 + .5),
transformOrigin: _origin,
transformPerspective: _perspective,
ease: Linear.easeNone
});
TweenLite.to(_me, .4, {
rotationX: 0,
rotationY: 0,
transformOrigin: _origin,
delay: .1,
transformPerspective: _perspective,
ease: Back.easeOut
});
//TweenLite.to(_black, .3, {autoAlpha:.05, ease:Quad.easeOut});
}
_this.getTileW = function() {
return _tileW;
}
}
//Event util
function CPCustomEvent(_name, _id) {
var e;
if (window.CustomEvent) e = new CustomEvent(_name, {
bubbles: true,
cancelable: true,
detail: _id
});
else {
e = document.createEvent('Event');
e.initEvent(_name, true, true, {
detail: _id
});
e.detail = _id;
}
return e;
}
&#13;
body {
margin: 0;
background: #f2f2f2;
}
.foldImg {
position: absolute;
left: 0;
top: 0;
}
.tile {
position: absolute;
left: 0;
top: 0;
visibility: hidden;
}
.tile .canvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.tile .shade {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: #f2f2f2;
}
&#13;
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js"></script>
<div class="camon-mobile img-responsive" id="camonMobileAnim"></div>
<div class="camon-sky img-responsive" id="camonSkyAnim"></div>
&#13;
虽然我仍在努力让这个响应并在滚动
上运行