2d карусель, работает, но уверен - неоптимально.
Недавно начал изучать js. Сталкивался с различными каруселями, путался в коде, когда хотел переделать под свои нужды. Пришел к тому, что на jquery быстрей свою состряпать. Но захотелось изучить как же это делается без сторонних фреймворков и плагинов. Почитал статью JS-Анимация (http://learn.javascript.ru/js-animation) и воспользовавшись предоставленным кодом, написал вот такую карусельку http://learn.javascript.ru/play/wnCIjb . Знаю, что сделал неоптимально и неуниверсально. Еще и запутался, когда оптимизировал, приделал кучу ненужных переменных, часть уже убрал. Буду рад, если наставите на путь истинный)) . Сейчас изучаю js дальше, хочу сделать, чтобы эта карусель анимировалась по нажатию и движению мышью. На эту тему лучше не подсказывайте, сделаю, дам ссылку и выслушаю критику.
Даю ссылку http://learn.javascript.ru/play/sKS3nc . Сделал, работает местами корявенько. На данный момент сделал так http://learn.javascript.ru/play/orjntb . Можно задавать количество картинок по горизонтали и вертикали, но в IE не работает автоматическое добавление недостающих картинок. Теперь и в ie работает. http://learn.javascript.ru/play/MWYWTb Добавил комментарии, старался поподробней (может кому приготится). http://learn.javascript.ru/play/nKxGNb |
alko, совет: не перебирай массивы циклом for..in. Во-первых, туда может прилететь что-нибудь из прототипа. Если, например, для кроссбраузерности добавить Array.prototype.forEach туда, где таких методов нет. Во-вторых, в массиве могут быть не только числовые ключи. Например, RegExp.prototype.exec возвращает массив Array, но в нём есть свойства index и
input. И это нормально. Я это к тому, что есть нормальные способы:
var idblock = ['lt','ct','rt','lm','cm','rm','lb','cb','rb'];
var button = idblock.map(function (id) {
return document.getElementById(id);
});
|
Спасибо. Не знал, что можно так использовать map, вообще в синтаксисе еще плаваю. http://learn.javascript.ru/play/unV86
|
alko,
на время одной анимации неплохобы незапускать другие либо заканчивать предыдущую - в jquery stop |
jquery в этой карусели не использую. Но об этом косяке знаю, на очереди. Вся конструкция рушится, если часто кликать по кнопкам.
|
Цитата:
|
что то типа var progress = stop || (new Date - start) / opts.duration;
stop = 0 нормальный ход. stop = 2 экстренное завершение |
Спасибо за совет, не хочу делать экстренное завершение анимации, наверное это будет не красиво, но переменную stop ввел http://learn.javascript.ru/play/TUvNsc .
|
Собери картинку, игрушка.
alko,
зарисовка на тему ... только перемещаются не блоки а background ... похоже но не совсем.
<!DOCTYPE HTML>
<html>
<head>
<title></title>
<style type="text/css">td.mouse{
height:98px;
width:98px;
text-align:center;
margin:0px;
background:url(http://dl9.glitter-graphics.net/pub/1432/1432279yonsqtq9b6.jpg) repeat;
border-radius:0px;
}
table{
border-collapse:collapse;
}
td.circle:after{
content:'';
display:block;
width:20px;
height:20px;
background:#F00;
border-radius:10px;
margin:25% auto;
}
td.circle{
height:20px;
width:20px;
text-align:center;
}
td{
transition:all 1s;
-moz-transition:all 1s;
-webkit-transition:all 1s;
-o-transition:all 1s;
}
</style>
</head>
<body>
<script language="JavaScript" type="text/javascript">
for (var l = 5, k, t = document.createElement("table"), c = 0; c < l; c++)
for (var tr = t.insertRow(c), s = 0; s < l; s++) {
k = 1;
if (0 == c || c == l - 1 || 0 == s || s == l - 1) k = 0;
var td = tr.insertCell(s),
n = 50 * (s - 1) + "% " + 50 * (c - 1) + "%";
k || s == c || 4 == s + c || (td.className = "circle", td.onclick = function (b, h) {
return function () {
for (var f, m = b && h ? -50 : 50,
q = document.querySelectorAll("td"),
g = b && 4 != b ? (f = b - 1, [6, 11, 16]) : (f = 5 * (h - 1), [6, 7, 8]), a = 0; a < g.length; a++) {
var p = q[g[a] + f],
d = getPosition(p);
p.style.backgroundPosition = b && 4 != b ? d[0] + "% " + (d[1] + m) + "%" : d[0] + m + "% " + d[1] + "%"
}
}
}(s, c));
k && (td.className = "mouse", td.style.backgroundPosition = n)
}
t.cellspacing = "0";
t.cellpadding = "0";
document.body.appendChild(t);
function getPosition(a) {
a = (window.getComputedStyle ? getComputedStyle(a, null) : a.currentStyle).backgroundPosition;
a = a.match(/-?\d+(\.\d+)?/g) || [0, 0];
a[0] = 50 * Math.round(a[0] / 50);
a[1] = 50 * Math.round(a[1] / 50);
return a
};
function go(a) {
var b = document.querySelectorAll("td.circle");
a--;
var c = Math.floor(Math.random() * b.length);
b[c].onclick();
a && window.setTimeout(function () {
go(a)
}, 1500)
};
</script>
<input type="button" name="" value="go" onclick="go(5)"/>
</body>
</html>
|
рони, очень интересно, коротко и эффективно. Дня два у меня наверное уйдет, чтоб разобраться в логике зарисовки.. Тоже думал сделать перемещение фонов, потому как, если инициировать анимацию "щипком" мыши, то цепляешь изображение вставленное в блок (что не красиво).
И сделал http://learn.javascript.ru/play/56G7kb |
Доделал http://learn.javascript.ru/play/sKS3nc .
|
alko,
:) |
Сделал универсальный вариант. Можно задавать размеры картинок и количество по горизонтали и вертикали. Если картинок не хватает, дополняются автоматически. Вот только при жестах мыши периодически выскакивает ошибка:
TypeError: blockmove[(colmove - 1)] is undefined newblock.style.background = blockmove[colmove -1].style.background; index.html (строка 224). При нажатии кнопок и автоматической анимации в начале, ее не возникает. Не пойму почему.. http://learn.javascript.ru/play/lZ9CSb |
alko,
строка 93 фигурные скобки пропущены |
рони, не вижу пропущенных скобок, где они должны быть? По поводу своей ошибки, тупо исключил ее, т.к. понять не могу http://learn.javascript.ru/play/xalZ3b . И заметил, что IE при недостающем количестве картинок и автоматическом их добавлении, не устанавливает стили части блоков.
|
Цитата:
{ } |
Может у меня галлюцинации.. строка 93? точно?
button.forEach(function(but, k) { but.onclick = function() { kuda(k); } }) |
alko,
http://learn.javascript.ru/play/k612cb строка 93 |
рони, спасибо, уже исправил. Там оно не нужно вообще. Вот что делать с ie? При присвоении бэкграунда новому блоку в 48 строке http://learn.javascript.ru/play/RLGdrb , в ie происходит удаление из массива блока бэкграунд которого присваивается (причем поэкспериментировав выяснил, что присваивается и содержимое блока удаляясь из исходного). И в итоге ему не назначаются стили высоты, ширины и топ, лефт, то есть он не отображается в итоге. Почему так происходит и как это исправить? В остальном вроде все работает.
Я не прав, удаление из массива не происходит, но эти элементы все равно не обрабатываются как в др. браузерах. И ie 8 строит как надо, а более поздние версии этого не делают. |
alko,
newblock.style.background = cont[dop].style.background; попробуйте перечислять что необходимо backgroundСolor и т.д. |
рони, пробовал присваивать только backgroundImage, результат тот же.
|
даже если везде поменять бэкграунд на бэкграунд имидж:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>2dcarusel</title>
<style type="text/css">
html, body{
width:100%;
}
html, body, div{
margin:0;
padding:0;
border:0;
}
#contcar{
position:relative;
top:50px;
margin:0 auto;
}
#container{
position:relative;
overflow:hidden;
}
#container div, #contcar div{
display:block;
position:absolute;
}
</style>
<script type="text/javascript" language="JavaScript">
window.onload = function(){
var width = 150; //ширина одного изображения
var height = 100; //высота одного изображения
var colx = 3; //количество изображений по горизонтали
var coly = 4; //количество изображений по вертикали
var but_size = 15; //размер кнопки по горизонтали (если справа или слева) или вертикали (если сверху или снизу)
var butbackground_ud = 'url(ud.jpg) no-repeat 0 0'; //изображение кнопки сверху или снизу от контейнера
var butbackground_lr = 'url(lr.jpg) no-repeat 0 0'; //изображение кнопки слева или справа от контейнера
var container = document.getElementById('container');
container.style.width = width * colx + 'px';
container.style.height = height * coly + 'px';
document.getElementById('contcar').style.width = width * colx + 'px';
document.getElementById('contcar').style.height = height * coly + 'px';
var cont = container.getElementsByTagName('div');
/* for (var i = 0; i < cont.length; i++) cont[i].innerHTML = i; */
var dop = 0;
while (cont.length < colx * coly) {
cont[cont.length] = cont[dop];
var dopblock = document.createElement('div');
dopblock.style.backgroundImage = cont[dop].style.backgroundImage;
container.appendChild(dopblock);
dop++;
}
cont = container.getElementsByTagName('div');
var block = [];
for (var i = 0; i < colx * coly; i++) block[i] = cont[i];
var idblock = [];
for (var i = 0; i < coly; i++){
for (var j = 0; j < colx; j++){
var bl = block[i * colx + j];
bl.style.width = width + 'px';
bl.style.height = height + 'px';
bl.style.left = width * j + 'px';
bl.style.top = height * i + 'px';
bl.id = 'b' + (i * colx + j);
idblock[i * colx + j] = bl.id;
/* console.log(bl.id); */
}
}
var button = [];
for (var i = 0; i < 2 * (colx + coly); i++) {
var but = document.createElement('DIV');
if (i < colx * 2) {
but.style.background = butbackground_ud;
but.style.width = width + 'px';
but.style.height = but_size + 'px';
but.style.left = ((i < colx) ? i * width : (i - colx) * width) + 'px';
but.style.top = ((i < colx) ? - but_size : coly * height) + 'px';
}
else {
but.style.background = butbackground_lr;
but.style.width = but_size + 'px';
but.style.height = height + 'px';
but.style.left = ((i > 2 * colx + coly - 1) ? colx * width : - but_size) + 'px';
but.style.top = ((i > 2 * colx + coly - 1) ? (i - 2 * colx - coly) * height : (i - 2 * colx) * height) + 'px';
}
but.style.cursor = 'pointer';
but.id = 'but' + i;
document.getElementById('contcar').appendChild(but);
button[i] = document.getElementById('but' + i);
}
var stop = 0;
var z = setInterval(function() {
kuda (Math.floor(Math.random() * (2 * (colx + coly))));
}, 1000);
button.forEach(function(but, k) {
but.onclick = function() {
kuda(k);
}
})
var x, y;
var curblock;
window.onmousedown = startmove;
function startmove(e) {
clearInterval(z);
x = e.pageX;
y = e.pageY;
curblock = whichblock();
window.onmousemove = wichmove;
}
function wichmove(e) {
if (curblock != null) {
setTimeout(function() {
var x1 = e.pageX - x;
var y1 = e.pageY - y;
var r;
if (Math.abs(x1) > Math.abs(y1)) {
if (x1 > 0) {
r = 2 * colx + coly + Math.floor(curblock / colx);
}
else if (x1 < 0) {
r = 2 * colx + Math.floor(curblock / colx);
}
}
else if (Math.abs(x1) < Math.abs(y1)) {
if (y1 < 0) {
r = curblock % colx;
}
else if (y1 > 0) {
r = colx + curblock % colx;
}
}
kuda(r);
x1 = 0;
y1 = 0;
window.onmousemove = false;
}, 50);
}
return false;
}
function whichblock() {
var cur = null;
block = idblock.map(function (id) {
return document.getElementById(id);
});
for (var i = 0; i < block.length; i++) {
if (
(block[i].offsetLeft < x - document.getElementById('contcar').offsetLeft) &&
(block[i].offsetLeft + block[i].offsetWidth > x - document.getElementById('contcar').offsetLeft) &&
(block[i].offsetTop < y - document.getElementById('contcar').offsetTop) &&
(block[i].offsetTop + block[i].offsetHeight > y - document.getElementById('contcar').offsetTop)
) {
cur = i;
break;
}
}
return cur;
}
function kuda(k) {
if (stop == 0) {
stop = 1;
block = idblock.map(function (id) {
return document.getElementById(id);
});
var a;
var b;
var size1;
var size2;
var prop1;
var prop2;
var step;
var m;
var colmove;
var blockmove = [];
var current = 0;
if (k < colx * 2) {
size1 = height;
size2 = width;
prop1 = 'top';
prop2 = 'left';
colmove = coly;
if (k < colx) {
step = -1;
m = k;
}
else {
step = 1;
m = k - colx;
}
}
else {
size1 = width;
size2 = height;
prop1 = 'left';
prop2 = 'top';
colmove = colx;
if (k < 2 * colx + coly) {
step = -1;
m = k - 2 * colx;
}
else {
step = 1;
m = k - 2 * colx - coly;
}
}
for (var i = 0; i < coly; i++){
for (var j = 0; j < colx; j++){
var bl = block[i * colx + j];
if (k < colx * 2) {
if (m == j) {
blockmove[current] = bl;
current++;
}
}
else {
if (m == i) {
blockmove[current] = bl;
current++;
}
}
}
}
var newblock = document.createElement('div');
newblock.style.width = width + 'px';
newblock.style.height = height + 'px';
if (blockmove[blockmove.length - 1] != null) {
if (step == 1) {
newblock.style.backgroundImage = blockmove[blockmove.length - 1].style.backgroundImage;
newblock.style[prop1] = - size1 + 'px';
blockmove.unshift(newblock);
a = 1;
}
else {
newblock.style.backgroundImage = blockmove[0].style.backgroundImage;
newblock.style[prop1] = colmove * size1 + 'px';
blockmove.push(newblock);
a = 0;
}
newblock.style[prop2] = m * size2 + 'px';
container.appendChild(newblock);
for (var i = 0; i < blockmove.length; i++) {
move(blockmove[i], prop1, (i - a) * size1, (i - a + step) * size1);
}
setTimeout(function() {
if (step == 1) {
for (var i = 0; i < colmove; i++) blockmove[i].id = blockmove[i + 1].id;
container.removeChild(blockmove[colmove]);
}
else{
for (var i = colmove; i > 0; i--) blockmove[i].id = blockmove[i - 1].id;
container.removeChild(blockmove[0]);
}
stop = 0;
}, 350);
}
else {
stop = 0;
}
}
}
};
function move(elem, prop, start, end) {
animateProp({
delay: 10,
duration: 300,
delta: makeEaseInOut(quad),
start: start,
end: end,
prop: prop,
elem: elem
});
}
function animate(opts) {
var start = new Date;
var delta = opts.delta || linear;
var timer = setInterval(function() {
var progress = (new Date - start) / opts.duration;
if (progress > 1) progress = 1;
opts.step( delta(progress) );
if (progress == 1) {
clearInterval(timer);
opts.complete && opts.complete();
}
}, opts.delay || 13);
return timer;
}
function animateProp(opts) {
var start = opts.start, end = opts.end, prop = opts.prop;
opts.step = function(delta) {
var value = Math.round(start + (end - start)*delta);
opts.elem.style[prop] = value + 'px';
}
return animate(opts);
}
function quad(progress) {
return Math.pow(progress, 2);
}
function makeEaseInOut(delta) {
return function(progress) {
if (progress < .5)
return delta(2*progress) / 2;
else
return (2 - delta(2*(1-progress))) / 2;
}
}
</script>
</head>
<body>
<div id="contcar">
<div id="container">
<div style="background-image:url(1.jpg);"></div>
<div style="background-image:url(2.jpg);"></div>
<div style="background-image:url(3.jpg);"></div>
<div style="background-image:url(4.jpg);"></div>
<div style="background-image:url(5.jpg);"></div>
<div style="background-image:url(6.jpg);"></div>
<div style="background-image:url(7.jpg);"></div>
<div style="background-image:url(8.jpg);"></div>
<div style="background-image:url(9.jpg);"></div>
</div>
</div>
</body>
</html>
|
Нашел ошибку, убрал строку 47, если посмотреть в предыдущий пост. Теперь в ie выше 8й версии работает нормально. Сейчас добавлю в шапку окончательный вариант. Окончательный, т.к. далее вылизывать код смысла не вижу, делал это с целью обучения.
|
| Часовой пояс GMT +3, время: 13:49. |