Обучение canvas:Использование картинок
Материал из MDC.
Содержание |
Одним из наиболее привлекательных свойств canvas является возможность использовать картинки (изображения). Оно может быть применено для реализации динамических фотокомпозиций, для создания фонов графиков и т.п. Также, это свойство является единственным способом размещения текста на canvas (В спецификации нет ни одной функции для рисования текста). Внешние изображения могут быть любого формата, поддерживаемого Gecko (т.е. форматы PNG, GIF или JPEG). Другие элементы canvas на этой же странице также могут быть использованы как источники изображений.
[править] Импортирование картинок
Обычно импортирование картинок происходит в два этапа:
- Сначала нам нужна ссылка на объект JavaScript Image или на другой элемент canvas, как источник. Не возможно использовать картинки просто передавая URL/путь до них.
- Потом мы рисуем картинку на canvas, используя функцию
drawImage.
Давайте сначала рассмотрим первый шаг. Доступны четыре варианта:
[править] Использование изображений с текущей страницы
Мы можем получить доступ к любому изображению на странице, используя коллекцию document.images, метод document.getElementsByTagName , либо, если нам известен атрибут ID изображения, метод document.getElementById.
[править] Использование другого элемента canvas
Как и к нормальным изображениям, мы можем получить доступ к элементам canvas через метод document.getElementsByTagName или метод document.getElementById. Перед тем, как вы будете использовать canvas как источник, убедитесь, что вы что-либо уже нарисовали на нём.
Один из наиболее практичных вариантов использования этого метода - создание маленьких превью-картинок для больших изображений canvas.
[править] Создание изображения с нуля
Ещё один вариант - создавать в нашем скрипте новые объекты Image. Главный недостаток такого подхода в том, что если мы не хотим, чтобы наш скрипт "зависал" посередине в ожидании загрузки изображения, нам нужно средство предварительной загрузки изображений.
Чтобы создать новый объект-картинку, мы делаем следующее:
var img = new Image(); // Создаём новый объект Image img.src = 'myImage.png'; // Устанавливаем путь к источнику
Когда этот скрипт выполняется, изображение начинает загружаться. Если к моменту исполнения инструкции drawImage загрузка ещё не закончилась, скрипт "подвисает" до её окончания. Если вы не хотите, чтобы такое случилось, используйте обработчик события onload:
var img = new Image(); // Создать новый объект Image
img.src = 'myImage.png'; // Установить путь к источнику
img.onload = function(){
// выполнить drawImage здесь
}
Если вы используете всего одно внешнее изображение, то такой подход хорош, но при работе более чем с одной картинкой лучше придумать что-нибудь похитрее. Рассмотрение различных тактик предварительной загрузки изображений выходит за рамки этой статьи, но здесь вы можете получить уже законченное решение.
[править] Embedding an image via data: url
Another possible way to include images is via the data: url. Data urls allow you to completely define an image as a Base64 encoded string of characters directly in your code. One advantage of data urls is that the resulting image is available immediately without another round trip to the server. ( Another advantage is that it is then possible to encapsulate in one file all of your CSS, Javascript, HTML, and images, making it more portable to other locations. ) Some disadvantages of this method are that your image is not cached, and for larger images the encoded url can become quite long:
var img_src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw==';
[править] drawImage
Once we have a reference to our source image object we can use the drawImage method to render it to the canvas. As we we'll see later the drawImage method is overloaded and has three different variants. In its most basic form it looks like this.
drawImage(image, x, y)
Where image is a reference to our image or canvas object. x and y form the coordinate on the target canvas where our image should be placed.
[править] drawImage example 1
In the following example I will be using an external image as the backdrop of a small line graph. Using backdrops can make your script considerably smaller because we don't need to draw an elaborate background. I'm only using one image here so I use the image object's onload event handler to execute the drawing statements. The drawImage method places the backdrop on the coordinate (0,0) which is the top left corner of the canvas.
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function(){
ctx.drawImage(img,0,0);
ctx.beginPath();
ctx.moveTo(30,96);
ctx.lineTo(70,66);
ctx.lineTo(103,76);
ctx.lineTo(170,15);
ctx.stroke();
}
img.src = 'images/backdrop.png';
}
[править] Scaling
The second variant of the drawImage method adds two new parameters and it allows us to place scaled images on the canvas.
drawImage(image, x, y, width, height)
Where width and height is the image's size on the target canvas.
[править] drawImage example 2
In this example I'm going to use an image as a wallpaper and repeat it several times on the canvas. This is done simply by looping and placing the scaled images at different positions. In the code below the first for loops through the rows the second for loop the columns. The image is scaled one third of its original size which is 50x38 pixels. We'll see how this could also have been achieved, by creating a custom pattern, later in this tutorial.
Note: Images can become blurry when scaling up or grainy if they're scaled down to much. Scaling is probably best not done if you've got some text in it which needs to remain legible.
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function(){
for (i=0;i<4;i++){
for (j=0;j<3;j++){
ctx.drawImage(img,j*50,i*38,50,38);
}
}
}
img.src = 'images/rhino.jpg';
}
[править] Slicing
The third and last variant of the drawImage method has eight new parameters. We can use this method to slice parts of a source image and draw them to the canvas.
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
image, just as with the other variants, is either a reference to an image object or a reference to a different canvas element. For the other eight parametes it's best to look at the image on the right. The first four parameters define the location and size of the slice on the source image. The last four parameters define the position and size on the destination canvas.
Slicing can be a useful tool when you want to make compositions. You could have all elements in a single image file and use this method to composite a complete drawing. For instance, if you want to make a chart you could have a PNG image containing all the necessary text in a single file and depending on your data could change the scale of your chart without very much diffculty. Another advantage is that you don't need to load every image individually.
[править] drawImage example 3
In this example I'm going to use the same rhino as we've seen above, but now I'm going to slice its head out and composite it into a picture frame. The image of the picture frame includes a dropshadow which has been saved as a 24-bit PNG image. Because 24-bit PNG images include a full 8-bit alpha channel, unlike GIF and 8-bit PNG images, I can place it onto any background and don't have to worry about a matte color.
I took a different approach to the loading of the images than the example above. I just placed the images directly in my HTML document and used a CSS rule to hide them from view (display:none). I assigned both images an id attribute to make them easier to select.
The script itself is very simple. I first draw the sliced and scaled image on the canvas (first drawImage statement), and then place the frame on top (second drawImage statement).
function draw() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Draw slice
ctx.drawImage(document.getElementById('source'),
33,71,104,124,21,20,87,104);
// Draw frame
ctx.drawImage(document.getElementById('frame'),0,0);
}
[править] Art gallery example
In the final example of this chapter I've made a little art gallery. The gallery consists of a table containing several images. When the page is loaded, for each image in the page a canvas element is inserted and a frame is drawn arround it.In my case, all images have a fixed width and height, and so does the frame that's drawn around it. You could enhance the script so that it uses the image's width and height to make the frame fit perfectly around it.
The code below should be self-explanatory. We loop through the images array and add new canvas elements accordingly. Probably the only thing to note, for those not so familar with the DOM, is the use of the insertBefore method. insertBefore is a method of the parent node (a table cell) of the element (the image) before which we want to insert our new node (the canvas element).
function draw() {
// Loop through all images
for (i=0;i<document.images.length;i++){
// Don't add a canvas for the frame image
if (document.images[i].getAttribute('id')!='frame'){
// Create canvas element
canvas = document.createElement('CANVAS');
canvas.setAttribute('width',132);
canvas.setAttribute('height',150);
// Insert before the image
document.images[i].parentNode.insertBefore(canvas,document.images[i]);
ctx = canvas.getContext('2d');
// Draw image to canvas
ctx.drawImage(document.images[i],15,20);
// Add frame
ctx.drawImage(document.getElementById('frame'),0,0);
}
}
}