Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

Posts Tagged ‘JavaScript

Логуючий фільтр для Angular expression

with one comment

Вирази в Angular (те що в фігурних дужках і ngBind) – не зовсім те що Javascript. Так каже документація.

Context: JavaScript expressions are evaluated against the global window. In Angular, expressions are evaluated against a scope object.

А тому ми не можемо там використати console.log. Але можемо написати наприклад такі фільтри:

    angular
        .module('starter')
        .filter('log', function() {
            // do not change value, but log it in console
            return function(input) {
                console.log(input);
                return input;
            };
        })
        .filter('justlog', function() {
            // do not render value but log it in console
            return function(input) {
                console.log(input);
                return '';
            };
        });

Хоча напевне існує якийсь правильніший, вже вбудований спосіб зневадження в Angular. 🙂

Written by bunyk

Лютий 25, 2016 at 15:52

Оприлюднено в Кодерство, Павутина

Tagged with ,

Вступ в AngularJS (1)

with 3 comments

Я почав писати цей конспект від початку 2015-го, за цей час вийшов AngularJS 2, напевне варто переписати. Хоча другий Angular написаний на TypeScript, тому він напевне вже не JS. Або вивчити React і написати конспект для нього. Вибір безмежний. 🙂

Написано на основі шикарного курсу від Code School. Просто щоб не передивлятись кожного разу перед тим як знову засвербить щось написати для фронт-енду.

Angular.js дозволяє писати шаблони прямо в HTML, розширюючи його своїми директивами, а потім автоматично заповнюючи даними.

Директива – це маркер (атрибут тегу) чи тег HTML що каже Angular-у запустити якийсь JavaScript код.

Єдиний файл що потрібен для початку роботи – angular.js.

Модулі

Код в Angular.js поміщається в модулі. Модулі містять код і описують залежності.

Щоб створити модуль пишемо:

var app = angular.module('store', []);

Перший аргумент – назва модуля, другий – список залежностей (якщо без залежностей – то порожній).

Тоді в html пишемо:

<html ng-app="store">

І це запустить наш модуль коли документ завантажиться.

І хоча наш модуль нічого не робить, але його включення вже допомагає розглядати код html який ми пишемо як директиви Angular.

Після чого можна писати на сторінці вирази. Як от

<p>2 + 2 = {{2 + 2}}</p>

Контролери

Щоб передати дані з JS в HTML, потрібно використати контролер:

var gem = {
    name: 'Dodecahedron',
    price: 10,
};

app.controller('StoreController', function() {
    this.product = gem;
});

Важливо щоб контролери називались КемелКейсом і останнім словом завжди було Controller.

Далі, в html, пишемо

<div ng-controller="StoreController as store">
<h1>{{store.product.name}}</h1>
<h2>{{store.product.price}}</h2>
</div>

store – аліас який ми описали і що використовується всередині виразів. Доступний лише всередині елементу для якого описаний контролер.

Директиви

ng-show – покаже елемент лише коли значення виразу істинне.

<div ng-controller="StoreController as store">
<button ng-show="store.product.canPurchase">Add to Cart</button>
</div>

ng-hide – навпаки, сховає елемент коли значення істинне.

ng-repeat – повторить елемент ітеруючи по якомусь списку.

ng-click – виконає код написаний всередині значення директиви при кліку по ньому.
ng-init – виконає код написаний всередині значення директиви при відображенні сторінки. Не користуйтесь ним, покладіть код який хочете покласти туди, всередину контролера.

<div ng-controller="StoreController as store">
<div ng-repeat="product in store.products">
<button ng-show="product.canPurchase">Add to Cart</button>
</div>
</div>

ng-src – директива що встановлює значення атрибуту src в тегу на зразок img. Тому що встановлення його значення через <img src="{{value}}">, призведе, перед тим як спрацює Angular, до спроби браузера завантажити файл “{{value}}“, і помилки 404. А цього ми не хочемо.

ng-class="{ 'class1': condition1, class2: condition2 }" – дозволяє додавати і забирати класи з елемента залежно від значення виразів умов.

Фільтри

При виводі даних в шаблонах, їх можна пропускати через фільтри. Загальний синтаксис:

<p>2 + 2 = {{вираз|фільтр:опції}}</p>

<!-- або так: -->
<li ng-repeat="product in store.products | limitTo:3 | orderBy:'-price'">

Форми

Директива ng-model прив’язує значення елемента форми до моделі (атрибута контролера). Вони оновлюються автоматично.

Щоб якийсь код виконувався коли форма відправляється, ми додаємо цей код в значення директиви ng-submit. І дописуємо директиву novalidate, щоб вимкнути стандартну валідацію HTML.

<form name="reviewForm"
      ng-controller="ReviewController as reviewCtrl"
      ng-submit="reviewForm.$valid && reviewCtrl.addReview(product)" 
      novalidate
>

Angular автоматично додає до полів класи – ng-pristine – до поля до якого ще не додавали код, ng-dirty – до зміненого поля, і ng-invalid – до поля що не проходить валідацію, та ng-valid – до того що проходить.

Поля валідуються по атрибуту type. Може бути наприклад email, url, number (додатково є атрибути min, max).

Далі в курсі (ось слайди) ще йдеться про те як

  • включати розмітку з інших файлів
  • писати власні директиви і власні html елементи
  • завантажувати дані через XHR

Щоправда, цього не треба щоб написати застосунок який я хочу написати. Але Про нього пізніше, бо github лежить, і вже трохи пізно. 🙂

Written by bunyk

Лютий 18, 2016 at 00:02

Оприлюднено в Кодерство, Павутина

Tagged with

Як намалювати стрілочку в SVG

leave a comment »

Креслення стрілочки, з позначенням деяких змінних

Креслення стрілочки, з позначенням деяких змінних

Поточна ситуація така, що на запит “як намалювати стрілочку”, Google видає купу порад дівчатам про те як зашпаклювати лице. Але проблема трапляється часто, і не тільки в SVG, ось наприклад старий пост про те як малювати вектори в OpenGL, для програмки що проводить структурний аналіз кінематики машин і механізмів. Тому треба виправити цю ситуацію, і написати ще пару публікацій про малювання стрілочок. 🙂

Тут буде код який було весело писати, і яким варто поділитись. Присутній також JsFiddle. Код дозволяє малювати стрілочки наступного вигляду:

arrows


Написано з використанням D3.js, але код можна причепити де завгодно, так як головне тут – функція arrow_path, яка генерує значення атрибуту d для тега path. Приймає вона координати початку і кінця стрілки, ширину лінії стрілки, радіус (задає розмір трикутника на кінці стрілки, і радіус gizmo (пімпочки на середині)). directed – булевий аргумент, що вказує чи малювати стрілочку на кінці лінії взагалі. gizmo – якщо false – пімпочки не буде, 'circle' – буде коло, 'diamond' – буде ромбик.
Прочитати решту цього запису »

Written by bunyk

Грудень 1, 2015 at 19:50

Оприлюднено в Графіка, Кодерство

Tagged with , ,

D3: фіксація вузла в графі

with 4 comments

Knowledge is power – it’s measured in WAT?!s (Rose Ames)

Я все мрію написати детективну історію на зразок “Шерлок Холмс і Бага Баскервілів”, але ніяк не підберу багу аби сюжет був достатньо гостросюжетним. Ось наприклад поділюсь знанням цікавої особливості D3.js при малюванні графів за допомогою фізичної симуляції. Наприклад ми хочемо деякі вузли графа розміщувати вручну.

Документація пише:

Each node has the following attributes: …
fixed – a boolean indicating whether node position is locked.

Ок, тоді давайте при кліку по вузлі, показувати меню, в якому є галочка “фіксувати ноду”. В коді що показує меню пишемо:

pin_down.setChecked(data.fixed);

І чомусь, не залежно від того фіксований вузол, чи ні, галочка завжди стоїть:

pin

Я почав логувати data.fixed, виявилось що вона отримує значення то 6, то 7, то 3… Зовсім не булевські. Я думав вже що десь якийсь код думає що fixed на вузлі графа означає щось інше.

Документація бреше. Виявилось що fixed – не булева змінна.

Internally, the force layout uses three bits to control whether a node is fixed. The first bit can be set externally, as in this example. The second and third bits are set on mouseover and mousedown, respectively, so that nodes are fixed temporarily during dragging. Although the second and third bits are automatically cleared when dragging ends, the first bit stays true in this example, and thus nodes remain fixed after dragging. (Sticky Force Layout).

Ну що ж, давайте по масці виділяти перший біт:

pin_down.setChecked(data.fixed && 1);

Все одно завжди поставлена? Ааа, ну так, && – це логічна кон’юнкція, а не побітова. 6 && 1 – true. Нам треба побітову.

pin_down.setChecked(data.fixed & 1);

Resolve issue -> Fixed.

Тепер залишилось придумати як в такий детектив додати персонажів і саспенсу. 😀

Written by bunyk

Червень 3, 2015 at 16:51

Оприлюднено в Графіка, Кодерство, Павутина

Tagged with

Додекалендар

with one comment

Я вирішив стати майстром верстки, CSS3, SVG і всяких інших крутих штук. Для цього вирішив забабахати календар на гранях додекаедра, розгортку якого можна подивитись на моєму гітхабі: http://bunyk.github.io/dodecahedron/

Календар на гранях додекаедра вигідний тим, що це оригінально, бо 3d, а ще ним добре грати футбол чи інші ігри з м’ячем. 🙂

Так як я на це вбив майже половину вихідних (5 з половиною годин замість трьох запланованих), і вже не маю сил написати рендеринг власне табличок для місяців, бо треба ще вирішити чи залишати текст в тегу <pre>, чи зверстати місяці табличками, то вирішив просто написати про це тут, може хтось хто в веб-дизайні розбирається краще, щось мені порадить і прискорить роботу.

Далі я ще планую зробити кнопочку яка дозволяє змінити рік (аби в 2015 заново не кодити), і кнопочки що дозволяють змінити фонові картинки. Тоді залишатиметься лише роздрукувати на A3 і можна клеїти комусь подарунок до нового року.

Найбільше сил пішло на те, щоб вирішити що React чомусь не хоче рендерити SVG, з D3 доведеться писати море коду, а Angular – саме воно, і треба його трохи підучити. Мені дуже сподобалось, надалі намагатимусь писати на ньому більше.

Розгортка і моделька

Розгортка і моделька з листка A4

А зовсім круті нерди можуть зробити аналогічний календар за допомогою Tikz в \LaTeX.

Written by bunyk

Грудень 14, 2014 at 23:13

Вступ до D3

with 2 comments

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

Written by bunyk

Листопад 30, 2014 at 10:37

Оприлюднено в Графіка, Кодерство, Павутина

Tagged with

Шлях до JavaScript майстерності

leave a comment »

В 2013 почав писати оцейсписок, поки мій Python-проект ще не стартував, і мені дали тимчасово розгрібати купу JS:

  1. jQuery – ok, користуватись вмію, куди без нього.
  2. JavaScript: The Definitive Guide – за один раз не прочитаєш
  3. JavaScript: The Good Parts – за один раз прочитав, але варто перечитати.
  4. JavaScript Web Applications – можливо не найцікавіша книжка яку я читав, але з неї я дізнався про Spine.js, Backbone.js, underscore.js, та паттерн pub/sub.
  5. Прочитати про те як написання коду схоже на поезію
  6. Прочитати про об’єкт Class в Leaflet. Подумати що це варто було б окремою бібліотекою випускати, бо ж не в кожному проекті де треба ООП, треба карти…
  7. Почати модульно організовувати проекти, require.js
  8. Починати скрипти з декларації "use strict";.
  9. Пам’ятати про те що існує underscore.js, писати менше циклів.

А кінця шляху нема.

Нагадування 2014-го: І Smooth Coffescript варто дочитати.

Written by bunyk

Вересень 22, 2014 at 17:14

Оприлюднено в Кодерство, Павутина

Tagged with