Принцип копирования — различия между версиями
Wikiadmin (обсуждение | вклад) м (Замена текста — «<source lang="(.*)" first-line="(.*)">» на «<syntaxhighlight lang="$1" line start="$2" enclose="div">») |
Wikiadmin (обсуждение | вклад) м (Замена текста — «</source>» на «</syntaxhighligh>») |
||
Строка 6: | Строка 6: | ||
<syntaxhighlight lang="javascript" line start="1" enclose="div"> | <syntaxhighlight lang="javascript" line start="1" enclose="div"> | ||
var buffer = document.createElement('canvas'); | var buffer = document.createElement('canvas'); | ||
− | </ | + | </syntaxhighligh> |
Далее нарисуем в "buffer" изображение, которое хотим копировать: | Далее нарисуем в "buffer" изображение, которое хотим копировать: | ||
Строка 12: | Строка 12: | ||
var buf_ctx = buffer.getContext('2d'); | var buf_ctx = buffer.getContext('2d'); | ||
buf_ctx... // здесь рисуется нужное нам изображение | buf_ctx... // здесь рисуется нужное нам изображение | ||
− | </ | + | </syntaxhighligh> |
Чтобы скопировать полученное изображение из внутренней памяти на экран, воспользуемся функцией drawImage(): | Чтобы скопировать полученное изображение из внутренней памяти на экран, воспользуемся функцией drawImage(): | ||
<syntaxhighlight lang="javascript" line start="1" enclose="div"> | <syntaxhighlight lang="javascript" line start="1" enclose="div"> | ||
context.drawImage(buffer, x, y); | context.drawImage(buffer, x, y); | ||
− | </ | + | </syntaxhighligh> |
где "x", "y" - координаты, в которые копируется изображение. | где "x", "y" - координаты, в которые копируется изображение. | ||
Строка 190: | Строка 190: | ||
} | } | ||
− | </ | + | </syntaxhighligh> |
Файл '''"CopyPic_v1_release.html"''' | Файл '''"CopyPic_v1_release.html"''' | ||
<syntaxhighlight lang="html" line start="1" enclose="div"> | <syntaxhighlight lang="html" line start="1" enclose="div"> | ||
Строка 206: | Строка 206: | ||
</body> | </body> | ||
</html> | </html> | ||
− | </ | + | </syntaxhighligh> |
</toggledisplay> | </toggledisplay> | ||
Версия 18:55, 8 марта 2015
Виртуальная лаборатория > Принцип копированияЕсли какое либо сгенерированное изображение в программе повторяется много раз, то имеет смысл не рисовать его каждый раз заново, а копировать единожды нарисованное. Это позволит в несколько раз увеличить скорость работы программы. Далее будет продемонстрировано применение данного принципа при рисовании на HTML5 Canvas с помощью Javascript.
Для начала создадим новый элемент Canvas - "buffer". Он будет находиться во внутренней памяти программы, без вывода на экран. <syntaxhighlight lang="javascript" line start="1" enclose="div"> var buffer = document.createElement('canvas'); </syntaxhighligh>
Далее нарисуем в "buffer" изображение, которое хотим копировать: <syntaxhighlight lang="javascript" line start="1" enclose="div"> var buf_ctx = buffer.getContext('2d'); buf_ctx... // здесь рисуется нужное нам изображение </syntaxhighligh>
Чтобы скопировать полученное изображение из внутренней памяти на экран, воспользуемся функцией drawImage(): <syntaxhighlight lang="javascript" line start="1" enclose="div"> context.drawImage(buffer, x, y); </syntaxhighligh> где "x", "y" - координаты, в которые копируется изображение.
В программе ниже демонстрируется применение описанного принципа. В фукнции draw_star(color) генерируется изображение звезды с градиентом, color - цвет звезды. Функция generate_star_pics() с помощью draw_star(color) генерирует два различных типа звезд - фиолетовые (название буфера - stars1) и желтые (stars2).
После задается треугольная решетка, и запускается цикл setInterval(tick, 1000 / fps), который рассчитывает изменение положения узлов в решетке, и запускает функцию рисования системы - draw(). Данная функция копирует изображение звезды определенного цвета (определяемого параметром type) в нужные позиции.
Скачать программу: CopyPic_v1_release.zip Текст программы на языке JavaScript (разработчик Цветков Денис): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default"> Файл "CopyPic_v1_release.js" <syntaxhighlight lang="javascript" line start="1" enclose="div"> function Main_Copy_pic(canvas) {
canvas.onselectstart = function () {return false;}; // запрет выделения canvas
// Предварительные установки
var context = canvas.getContext("2d"); // на context происходит рисование
var a0 = 1; // масштаб расстояния
// *** Задание вычислительных параметров ***
var a = 2 * a0; // шаг решетки var N = 8.46 * a; // количество звезд по горизонтали
// *** Выполнение программы ***
var fps = 60; // количество кадров в секунду var scale = canvas.height / N; // масштабный коэффициент для перехода от расчетных к экранным координатам var w = canvas.width / scale; // ширина окна в расчетных координатах var h = canvas.height / scale; // высота окна в расчетных координатах
var points = []; var ax = a; // шаг по горизонтали var ay = a * Math.sqrt(3) / 2; // шаг по вертикали
function set_triangular_lattice() { // треугольная решетка for (var i = 0; i < Math.floor(w / ax) + 5; i++) { points[i] = []; for (var j = 0; j < Math.floor(h / ay) + 5; j++) { points[i][j] = []; points[i][j].x = (i - 2) * ax * scale + ax / 2 * (j % 2) * scale; points[i][j].y = (j - 2) * ay * scale; points[i][j].type = j % 2; } } }
// Предварительная генерация двух разных звезд var stars1, stars2; function generate_star_pics() { stars1 = draw_star("#8050cc"); // фиолетовые звезды stars2 = draw_star("#dd9922"); // желтые звезды } function draw_star(color) { var buffer = document.createElement('canvas'); var ctx = buffer.getContext('2d');
var n = 5; // углов у звезды var r = 0.35 * a * scale; // радиус звезды var fi = 0; // поворот звезды
// здесь звезда рисуется на невидимый канвас, с которого потом будет копироваться на видимый ctx.beginPath(); for(var i = 0; i <= (n * 2) + 1; i++) { var r_actual = r * (i % 2 + 1) / 2; var omega = 2 * Math.PI / (n * 2) * i; ctx.lineTo(((r_actual * Math.sin(omega + fi * 3.14 / 180)) + r), (r_actual * Math.cos(omega + fi * 3.14 / 180)) + r); } ctx.closePath(); var gradient = context.createRadialGradient(r, r, r, r, r, 0); gradient.addColorStop(0, color); gradient.addColorStop(1, color_light(color)); ctx.fillStyle = gradient; ctx.fill();
return buffer; } function color_light(col) { // осветление цвета для градиента, можно еще делать через схему HSV -> RGB var col_light = "#"; for (var i = 1; i < col.length; i++) { if (parseInt(col[i], 16) + 0x8 <= 0xf) col_light += (parseInt(col[i], 16) + 0x8).toString(16); else col_light += "f"; } return col_light; }
function tick() { move(); draw(); }
var phase1, phase2, phase3; var phase1_0 = 60, phase2_0 = 60, phase3_0 = 60; function init() { set_triangular_lattice(); phase1 = phase1_0; phase2 = phase2_0; phase3 = phase3_0; } function move() { // перемещение звезд var i, j, sign, p; if (phase1 > 0) { for (i = 0; i < points.length; i++) for (j = 0; j < points[i].length; j++) { if (j % 2 == 0) sign = 1; else sign = -1; points[i][j].x = points[i][j].x + sign * ax * scale / phase1_0; } phase1--; } else if (phase2 > 0) { p = 1; for (j = 0; j < points[0].length; j++) { for (i = 0; i < points.length; i++) { if (p >= 2) { if (i % 2 == 0) sign = 1; else sign = -1; } else { if (i % 2 == 1) sign = 1; else sign = -1; } points[i][j].x = points[i][j].x + sign * ax * scale / (phase2_0 * 2); points[i][j].y = points[i][j].y - sign * ay * scale / phase2_0; } if (p == 3) p = 0; else p++; } phase2--; } else if (phase3 > 0) { p = 0; for (j = 0; j < points[0].length; j++) { for (i = 0; i < points.length; i++) { if (p >= 2) { if (i % 2 == 0) sign = 1; else sign = -1; } else { if (i % 2 == 1) sign = 1; else sign = -1; } points[i][j].x = points[i][j].x + sign * ax * scale / (phase3_0 * 2); points[i][j].y = points[i][j].y + sign * ay * scale / phase3_0; } if (p == 3) p = 0; else p++; } phase3--; } else {init()} }
// Рисование function draw() { // очистка экрана context.fillStyle = "#000000"; context.fillRect(0, 0, w * scale, h * scale);
// копирование звезд в нужные позиции for (var i = 0; i < points.length; i++) for (var j = 0; j < points[i].length; j++) { if (points[i][j].type == 0) context.drawImage(stars1, points[i][j].x, points[i][j].y); else context.drawImage(stars2, points[i][j].x, points[i][j].y); } // звезда не рисуется в цикле каждый раз, когда нужна, она просто копируется в нужную точку. }
generate_star_pics(); // генерация изображений звезд происходит только один раз init(); setInterval(tick, 1000 / fps);
} </syntaxhighligh> Файл "CopyPic_v1_release.html" <syntaxhighlight lang="html" line start="1" enclose="div"> <!DOCTYPE html> <html> <head>
<meta charset="UTF-8" /> <title>Copy pic</title> <script src="CopyPic_v1_release.js"></script>
</head> <body>
<canvas id="Copy_pic_canvas" width="500" height="500" style="border:1px solid #000000;"></canvas>
<script type="text/javascript">var app = new Main_Copy_pic(document.getElementById('Copy_pic_canvas'));</script>
</body> </html> </syntaxhighligh> </toggledisplay>