Текущая версия |
Ваш текст |
Строка 1: |
Строка 1: |
| [[Виртуальная лаборатория]] > [[Принцип копирования]] <HR> | | [[Виртуальная лаборатория]] > [[Принцип копирования]] <HR> |
| | | |
− | Если какое либо сгенерированное изображение в программе повторяется много раз, то имеет смысл не рисовать его каждый раз заново, а копировать единожды нарисованное. Это позволит в несколько раз увеличить скорость работы программы. Далее будет продемонстрировано применение данного принципа при рисовании на HTML5 Canvas с помощью Javascript.
| |
− |
| |
− | Для начала создадим новый элемент Canvas - "buffer". Он будет находиться во внутренней памяти программы, без вывода на экран.
| |
− | <syntaxhighlight lang="javascript" line start="1" enclose="div">
| |
− | var buffer = document.createElement('canvas');
| |
− | </syntaxhighlight>
| |
− |
| |
− | Далее нарисуем в "buffer" изображение, которое хотим копировать:
| |
− | <syntaxhighlight lang="javascript" line start="1" enclose="div">
| |
− | var buf_ctx = buffer.getContext('2d');
| |
− | buf_ctx... // здесь рисуется нужное нам изображение
| |
− | </syntaxhighlight>
| |
− |
| |
− | Чтобы скопировать полученное изображение из внутренней памяти на экран, воспользуемся функцией drawImage():
| |
− | <syntaxhighlight lang="javascript" line start="1" enclose="div">
| |
− | context.drawImage(buffer, x, y);
| |
− | </syntaxhighlight>
| |
− | где "x", "y" - координаты, в которые копируется изображение.
| |
− |
| |
− |
| |
− | В программе ниже демонстрируется применение описанного принципа. В фукнции '''draw_star('''''color''''')''' генерируется изображение звезды с градиентом, ''color'' - цвет звезды. Функция '''generate_star_pics()''' с помощью '''draw_star('''''color''''')''' генерирует два различных типа звезд - фиолетовые (название буфера - '''stars1''') и желтые ('''stars2''').
| |
− |
| |
− | После задается треугольная решетка, и запускается цикл '''setInterval('''''tick, 1000 / fps''''')''', который рассчитывает изменение положения узлов в решетке, и запускает функцию рисования системы - '''draw()'''. Данная функция копирует изображение звезды определенного цвета (определяемого параметром ''type'') в нужные позиции.
| |
− |
| |
− | <htmlet nocache="yes">Tcvetkov/CopyPic/CopyPic_v1_release_TM</htmlet>
| |
− |
| |
− | Скачать программу: [[Медиа:CopyPic_v1_release.zip|CopyPic_v1_release.zip]]
| |
− | <div class="mw-collapsible mw-collapsed" style="width:100%" >
| |
− | '''Текст программы на языке JavaScript (разработчик [[Цветков Денис]]):''' <div class="mw-collapsible-content">
| |
− | Файл '''"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);
| |
− |
| |
− | }
| |
− | </syntaxhighlight>
| |
− | Файл '''"CopyPic_v1_release.html"'''
| |
− | <syntaxhighlight lang="html5" 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>
| |
− | </syntaxhighlight>
| |
− | </div>
| |
− | </div>
| |
| | | |
| | | |
| | | |
| [[Category: Виртуальная лаборатория]] | | [[Category: Виртуальная лаборатория]] |