Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Canvas Вывод изображений в цикле (https://javascript.ru/forum/dom-window/56989-canvas-vyvod-izobrazhenijj-v-cikle.html)

0leg9 13.07.2015 23:22

Canvas Вывод изображений в цикле
 
Пытаюсь вывести изображения на холст через цикл. Появляется только последняя картинка. В массиве data содержатся объекты со свойствами: путь к картинке, координаты x и y.
var canvas  = document.getElementById('canvas');
context = canvas.getContext('2d');
var obj;
for (var i = 0; i < data.length; i++) {
   obj = data[i];
   var image = new Image();
   image.src = obj.path;
   image.onload = function() {
      context.drawImage(image, obj.x, obj.y);
   };
};

0leg9 14.07.2015 00:19

В моем случае работает такой код:
var canvas  = document.getElementById('canvas');
context = canvas.getContext('2d');
var obj;
for (var i = 0; i < data.length; i++) {
   obj = data[i];
   draw(obj.path, obj.x, obj.y);
};
function draw (path, x, y) {
   var image = new Image();
   image.src = path;
   image.onload = function() {
      context.drawImage(image, x, y);
   };
};

рони 14.07.2015 00:31

0leg9,
описание вашей проблемы

Decode 14.07.2015 00:54

0leg9, может так у вас должно быть?

var data = ['http://placehold.it/50x50', 'http://placehold.it/100x100'];
var obj = {};

for (var i = 0; i < data.length; i++) {
    obj[i] = data[i];
}

console.log(obj);

рони 14.07.2015 01:29

Decode,
как у него должно он уже решил через замыкание данных строка 6 пост 2

Decode 14.07.2015 01:36

рони, ааа, все понял. Я чет не обратил внимание на второй пост.

kostyanet 14.07.2015 06:15

Цитата:

Сообщение от 0leg9
Появляется только последняя картинка

Когда ваш цикл мгновенно накидал в память отложенных операций, то аргументом obj каждой операции оказался один и то же объект из массива - самый последний. Потому что внутри цикла оно все - референс, ссылка.

Что там дал рони почитать - то будет понятно только тем, кто и так понимает.

Понимать надо разницу между передачей значения переменной по ссылке на переменную - by reference, и копии значения переменной - by value.

Например значения аргументов функции всегда копируются, если не указано иначе. Например в нормальном скрипте типа php:

Каноничная передача by val:

function foo($bar){ $bar.=' jump'; echo $bar;};


само собой значение переменной используемой в качестве аргумента не будет испорчено действиями функции.

$text='How to';

bar($text); // выведет How to jump

echo $text // вывод How to



А вот если передавать по ссылке

function foo(&$bar){ echo $bar;};


то

$text='How to';

bar($text); // выведет How to jump

echo $text // вывод How to jump


то функция "испортит" значение, поменяет его, запишет свое и в таком роде.

На жабе таких примеров не могу привести, она явно не дает определять режим.

Но ясно что внутри цикла все его аргументы крутятся by ref и все нормально работает если копируется в каждой итерации куда-то сразу же, не отходя от кассы (например в хтмл или в консоль). А если не копируется, а откладывается на будущее - то в будущем оказывается копия одного и то же значения у всех отложенных операций. Следовательно все что вам нужно это вручную скопировать текущее значение для будущего применения.

kostyanet 14.07.2015 07:27

Цитата:

Сообщение от рони
через замыкание данных строка 6 пост 2

Забавно. С каких это пор вызов функции сам по себе стал замыканием?

Короче, замыкание у него и так было, просто внутрь ничего не попадало. Это image.onload.

Цикл вряд ли тут вообще нужен, ибо порядок определяет не цикл, а скорость загрузки фоток. Чтобы все было четко по порядку, надо завести загрузку следующей в тот же самый обработчик.

Самый простой пример

var drawPath=function(){
	var canvas  = document.getElementById('canvas'),
	context = canvas.getContext('2d'),
	i=0,
	drawImage=function(){
		var obj=data[i++];
		if(obj){
			var image = new Image();
			image.onload=function(){
				context.drawImage(this, obj.x, obj.y);
				drawImage();
			};
			image.src=obj.path;
		}
	};
	drawImage();
};

drawPath();



для проверки

http://jsfiddle.net/z9nk1238/3/

ЗЫ Я сначала подумал что ТС рисует сегменты пути, потом только допер что - обычные фотки.

laimas 14.07.2015 08:15

Цитата:

Сообщение от kostyanet
то функция "испортит" значение

Да уж, определенице ничего не скажешь.

kostyanet 14.07.2015 08:30

Когда нечего сказать - молчат.

laimas 14.07.2015 08:45

Цитата:

Сообщение от kostyanet
Когда нечего сказать - молчат.

Ты если хочешь показаться умным, то хоть внимательно читай то, что бездумно копируешь.
Ничто не будет "испорчено", это не баба, которую портят в кустах, это аргумент, и в данном случае передача по ссылке, то есть изменяться будет то, на что указывает ссылка, а не аргумент. Умник хренов, несешь бред от поста к посту, изгадил весь форум своим словоблудием, даже заглядывать в посты из за тебя паразита не охота.

jackdempsey2015 14.07.2015 11:14

<html>

<canvas id="c"></canvas>


<script>

data=[
{path: "http://javascript.ru/forum/images/smilies/smile.gif", x: 10, y: 10},
{path: "http://javascript.ru/forum/images/smilies/wink.gif", x: 20, y: 20}
]
createImage=function(o){
 o.img=new Image
 o.img.src=o.path
 o.img.onload=function(){c.getContext("2d").drawImage(o.img, o.x, o.y)}
}
data.forEach(createImage)


</script>
</html>


ЗЫ то что выше советовали про замыкания -- не слушайте. Это, мягко говоря, неоптимальный вариант.

MallSerg 14.07.2015 11:49

foo эволюционирует =).
Любопытно как долго продержется этот акк

рони 14.07.2015 12:20

Цитата:

Сообщение от jackdempsey2015
ЗЫ то что выше советовали про замыкания -- не слушайте

Цитата:

Сообщение от jackdempsey2015
forEach

сахар этого же замыкания.

kostyanet 14.07.2015 12:30

Цитата:

Сообщение от laimas
Ничто не будет "испорчено", это не баба,

Сколько угодно глюков из-за рефов и я бы сказал что указатели народ не любит именно из-за того, что данные портятся.

Цитата:

Сообщение от jackdempsey2015
data.forEach(createImage)

Вы устройство этого форича гляньте. Но, еще раз, дело тут вовсе не в том что цикл, а в том, что порядок будет нарушен. Если он не важен, то не важен, а когда станет важен придется выкидывать цикл в какой бы ипостаси он не был и пихать хобот в ж. Иначе асинхрон не упорядочить.

jackdempsey2015 14.07.2015 12:44

>>Вы устройство этого форича
Если не устраивает скорость нативного, напишите свой
>>а в том, что порядок будет нарушен
никакого порядка там нет, событие наступает в порядке загрузки картинок, асинхронно, поэтому контролировать этот порядок невозможно, Можно синхронизировать загрузку, но это уже другая история.

jackdempsey2015 14.07.2015 12:57

Цитата:

Сообщение от рони
сахар этого же замыкания.

forEach не создает никаких замыканий, он просто вызывает последовательно указанную функцию для каждого элемента. В некотором роде, замыкание там создается в самом обработчике onload. И то, фактически, это не замыкание, просто пробрасывание переменной, окружение там не создается, эта связка живет только в момент вызова, поэтому никакого оверхеда по памяти там нет. Но я говорил про явное создание анонимных замыканий.

laimas 14.07.2015 13:09

Цитата:

Сообщение от kostyanet
Сколько угодно глюков из-за рефов

Ты понятия не имеешь, что такое передача по ссылке и какова польза от них, как и многое другое не понимаешь, поэтому видимо и используешь этот тупой жаргон в стиле четких пацанчиков, а бы умным и крутым казаться.

Самое смешное, так это то, что к данной теме пост о передаче по ссылке как собаке пятая лапа.

kostyanet 14.07.2015 22:48

Цитата:

Сообщение от jackdempsey2015
поэтому контролировать этот порядок невозможно

На предыдущей странице есть рабочий пример с полным контролем этого самого порядка.

jackdempsey2015 15.07.2015 00:54

Цитата:

Сообщение от kostyanet
с полным контролем этого самого порядка.

нет у тебя там никакого контроля порядка, онлоад вызывается асинхронно, ты не можешь знать когда он отработает. В твоем коде он только назначен, то же самое что и в моем, никакой разницы, в этом отношении.

kostyanet 15.07.2015 04:52

Цитата:

Сообщение от jackdempsey2015
ты не можешь знать когда он отработает


Нормально пули отливаете.

Чтоб вас больше не мучить наводящими вопросами, объясню как оно работает:

Следующая картинка загружается в результате и после загрузки предыдущей и эта простая фича обеспечивает сохранение того порядка, который определен в контрольном массиве.

Кроме того циклы становятся не нужны, процесс зацикливается по событиям, а не счетчикам.

То есть куда попадет пуля не имеет значения. Не надо знать когда там что отработает, ибо как только - так сразу.

MallSerg 15.07.2015 05:28

Цитата:

Сообщение от kostyanet
Следующая картинка загружается в результате и после загрузки предыдущей

Лож, бред и ахинея. =)

kostyanet 15.07.2015 05:55

Цитата:

Сообщение от MallSerg
Лож, бред и ахинея. =)

Лошь, бред и ахинея.


Часовой пояс GMT +3, время: 20:52.