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, время: 02:31. |