Здесь необходимо понять две вещи.
Когда вы применяете преобразование к контексту, вы не применяете его к чему-либо уже нарисованному.Вы применяете преобразование только к тем вещам, которые примерно должны быть нарисованы.
Другими словами, всегда - это случай, когда вы искажаете изображения при их рисовании, используяDrawImage!Это единственный способ сделать это.
Есть исключение из этого правила, о котором вам следует помнить, поскольку вы используете imageData: размещение imageData на холсте идеально подходит для пикселей и игнорирует любую матрицу преобразования.
Так что, если вы хотите различный перекос для каждой тени, все, что вам нужно сделать, это преобразовать контекст, нарисовать вещь A, затем восстановить и преобразовать контекст другим способом и нарисовать вещь B.
Вот примериспользуя ваш код:
http://jsfiddle.net/QfrVB/
Кстати, вам совсем не обязательно использовать imageData.Его использование - очень медленная операция (важно, если вы создаете анимированное приложение, такое как игра), и вам следует избегать ее, если можете.
Вместо этого:
var imgd = ctx.getImageData(0, 0, 500, 300);
var pix = imgd.data;
//convert the drawn trees to shadows
for (var i = 0, n = pix.length; i < n; i += 4) {
pix[i ] = 0; // red
pix[i+1] = 0; // green
pix[i+2] = 0; // blue
// alpha
}
ctx.putImageData(imgd, 0, 0);
Вы можете просто сделать это:
ctx.globalCompositeOperation = 'source-atop';
ctx.fillStyle = 'black';
ctx.fillRect(0,0,500,300);
ctx.globalCompositeOperation = 'source-over'; // back to normal
Этот код рисует черный цвет над всеми пикселями, которые в настоящее время существуют на холсте.Так как сначала вы рисуете все тени, вы можете зачеркнуть их все одним вызовом fillRect таким образом.
Посмотрите на это здесь: http://jsfiddle.net/QfrVB/2/