Tag Archives: графіка - Page 2

Вступ до D3

D3 (розшифровується як DDD, що означає Data Driven Documents) – то бібліотека для написання JavaScript візуалізацій.

Бібліотеку можна скачати з сайту, або під’єднатись до CDN:

<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>

Тепер, щоб змінити наприклад текст якогось елемента, можна за допомогою d3 цей елемент вибрати, і відредагувати його текст:

d3.select('#field').text('hello world!')

Метод select приймає такі самі селектори CSS як і jQuery, тому тут нічого несподіваного для тих хто користувався jQuery (чи CSS) не повинно бути.

Можна також додавати елементи:

d3.select('body').append('p').text('hello world!')

Можна змінювати оформлення елементів:

d3.select('body')
   .append('p')
   .text('hello world!')
   .style('color', 'red')

Цих маніпуляцій з елементами вже досить щоб малювати щось з SVG:

var panel = d3.select('body');
var width = panel[0][0].clientWidth - 2;
var height = panel[0][0].clientHeight - 2;
var svg = panel.append('svg')
    .attr('width', width)
    .attr('height', height)
    .style('border', 'solid black 1px');

var circle = svg.append('circle')
    .attr('cx', width / 2)
    .attr('cy', height / 2)
    .attr('r', height / 2 - 1);

Тепер давайте додамо ще трішки кіл, і подивимось на відмінність між select та selectAll. Перший метод повертає лише перший знайдений елемент, а другий – всі.

for(var i = 0; i <= 10; i++) {
    svg.append('circle')
        .attr('r', 10)
        .attr('cy', height / 2);
};

var circles = svg.selectAll('circle');

Тепер ми можемо задати атрибут всім колам зразу. А можемо сказати що атрибут кожного кола повинен бути результатом обчислення функції. І передати замість значення – лямбду. Наприклад можна змусити наші кола скакати туди-сюди через певний інтервал:

setInterval(function() {
    circles.attr('cx', function() { return Math.random() * width });
}, 100);

Але випадкові функції то не цікаво. Давайте займемось чимось серйозним, і намалюємо графік функції. Для цього функцію треба буде кілька разів обчислити на певному проміжку:

var tabulate_function = function(f, a, b, count) {
    var f_data = [];
    var width = b - a;
    for(var i=0; i < count; i++) {
        f_data.push(f(a + i * width / count));
    };
    return f_data;
};

Передавши в функцію tabulate_function, функцію для табулювання, інтервал a, b, та кількість обчислень, ми отримуємо масив з даними:

var BARS_COUNT = 100;
var data = tabulate_function(Math.sqrt, 0, 10, BARS_COUNT);

Тепер, за допомогою методу data ми можемо прив’язати наші дані до вибірки з прямокутників. А також задати висоту прямокутника як функцію від даних, а його позицію – як функцію від номера елементу (і даних, хоча тут не використовуватимемо):

var bars = svg.selectAll('rectangle').data(data); // Прив’язуємо до вибірки з прямокутників
bars.enter().append('rect'); // А що якщо прямокутників нема (не вистачає)? Тоді додаємо прямокутник.

var bar_width = width / BARS_COUNT;

bars
    .attr('y', function(d) { return height - d * 100 }) // Позиція по осі Y як і висота функції від даних
    .attr('x', function(d, i) { return i * bar_width }) // Позиція по осі X - функція від номера елементу даних.
    .attr('width', bar_width)
    .attr('height', function(d) { return d * 100 });

Має вийти щось схоже на оце: sqrt. Якщо не вийшло – подивіться в чому відмінність вашого і мого коду.

Мені й самому дивно, для чого так незвично описувати залежність між даними й елементами. Але тут основна фішка в тому що ми можемо передати нашому зображенню нові дані, а воно не буде видаляти всі елементи і створювати їх заново, а змінить атрибути тих елементів які треба змінити, додасть нових елементів якщо їх бракує і видалить елементи які стали зайвими.

Щоб вони видалялись, не забудьте написати:

bars.exit().remove();

Тепер про оновлення. Хотілось би просто написати bars.data(new_data), але таке чомусь не працює. Тому треба заново знайти всі елементи, прив’язати до них дані і сказати їм як на ці дані реагувати.

В такому випадку, я виношу це все в функцію update:

var update_graph = function(data) {
    var bar_width = width / data.length;
    var bars = svg.selectAll('rect').data(data);

    bars.enter().append('rect');

    bars
      .attr('x', function(d, i) { return i * bar_width })
      .attr('width', bar_width)
      .transition().duration(2000) // Наступні атрибути змінювати плавно, за 2 секунди
      .attr('y', function(d) { return height - d * 100 })
      .attr('height', function(d) { return d * 100 });
    
    bars.exit().remove();  
};

І тоді, коли ми викличемо цю функцію кілька разів з різними даними – картинка буде плавно змінюватись, не перестворюючи надто багато елементів. А якщо видалити виклик transition().duration() – то буде змінюватись миттєво. Можна подивитись тут.

І на цьому напевне завершу мою розповідь, а то вона щось виходить нуднішою ніж я сподівався. А d3 не нудний, на ньому не тільки графіки можна малювати, а й наприклад прості іграшки.

Посилання

  1. JSFiddle – спонсор даної публікації. :) Всім рекомендую користуватись під час читання різноманітних підручників з веб дизайну.
  2. Scott Murray – Learning d3 (youtube)
  3. Mike Bostock – Three Little Circles
  4. Mike Bostock – Thinking With Joins

Filed under: Графіка, Кодерство, Павутина Tagged: JavaScript

Грандіозніше ніж всесвіт і фантастичніше за уяву

Фрактали всі вже бачили, всі вже знають, та все ж… Тут мова піде про світові рекорди. :)

Всесвіт настільки великий, що його розміри важко уявити. Всесвіт, досліджуваний астрономами, — частина матеріального світу, що доступна дослідженню астрономічними засобами, які відповідають досягнутому рівневі розвитку науки (часто цю частину всесвіту називають метагалактикою), простягається на 1,6\cdot 10^{27} метрів і нікому не відомо, наскільки він великий за межами видимої частини.

Атомне ядро має розмір 10^{-15} метрів.

Тепер, якщо ми маємо зображення всесвіту (в PNG наприклад :) ), то для того щоб побачити на ньому ядро атома потрібно збільшити його в 10^{42} рази. Уявляєте собі цей зум?

А тепер я вам покажу картинку, на якій роблять зум 8 \cdot 10^{606}. Це не в мільйони разів більше ніж оцей маштаб всесвіту. Це в мільйони мільонів мільйонів… і так повторити ще сто раз. Одним словом дивіться:

Для такого відео потрібна ефективна реалізація високоточної арифметики (це вам не double), написаної спеціалістом з оптимізації чисел з плаваючою комою компанії Valve, і дні і ночі обчислень на швидких багатоядерних комп’ютерах.

Те відео – здається світовий рекорд. Але думаю це не довго, бо зроблене воно більш ніж рік тому. Може з того часу хтось рік рендерив нове відео, і щоб побити рекорд залишилось ще кілька місяців обчислень?


Filed under: Всяке, Графіка Tagged: графіка, філософія

Моє XVideo позеленіло :(

Вчора не міг заснути. Мучило невирішене питання. Яким чином mplayer може рендерити купу fps в повноекранному режимі, встигаючи при цьому читати з диска і робити декодинг. В такому разі я повинен могти отримати ще більше fps при рендерингу якоїсь функції виду

RGB video(int x, int y, int frame);

Зранку встав і почитав про mplayer -vo help. Помилувався драйвером matrixview.

Почитав про X Video, там знайшов посилання на демо-код, і вирішив спробувати скомпілювати: “gcc -o testxv testxv.c -L/usr/X11R6/lib -lX11 -lXext -lXv“. Вийшло не зразу. Після встановлення пакетів libx11-dev, x11proto-video-dev, libxcb-xv0-dev, libxv-dev.

Скомпілювалось, і почав гратись. Чомусь ніяк не міг отримати ніякого кольору крім зеленого і чорного. Навіть написав функцію перетворення кольорової моделі з моєї улюбленої RGB в якусь незрозумілу YUV.

Може неправильно?

Нічого. А ще гірше, що коли змінив роздільну здатність, то fps впали до 10-15.

Отака пічалька. :(

Може використати SDL? Напевне я спробую SDL. Там hello world точно коротший.

P.S. Поки навіть не знаю що я хочу намалювати. Може потенціал електричного поля в системі з кількома рухомими зарядами, або анімацію якогось фрактальчика, але руки сверблять просто зробити і знати що я це можу.


Filed under: Графіка, Кодерство Tagged: С++, linux