Tag Archives: javascript - Page 2

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

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.

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


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

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

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

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

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

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

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

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

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

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


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

Вступ до 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

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

В 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 варто дочитати.


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

Заблоковано завантаження змішаного активного вмісту

З версії 23 (квітня 2013) Firefox забороняє завантаження змішаного активного вмісту, тобто ви не можете завантажувати на отримані через https сторінки скрипти (активний вміст) по http. Тому, якщо ви отримуєте таке повідомлення:

Заблоковано завантаження змішаного активного вмісту
"http://modernizr.com/downloads/modernizr-latest.js"

Треба якось захостити бібліотеку на сервері з https.

Або зайти на сторінку about:config і поставити налаштування security.mixed_content.block_active_content в false.


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

Прочитання коду гри 2048

От я їду в поїзді, інтернету нема, я забув скинути собі документацію з AngularJS, тому тепер не знаю чому не працює форма яку я написав по пам’яті. ng-value працює лише в одну сторону? Ах, точно, в іншу – ng-model. Тим не менш, я ще забув як визначити номер ітерації в ng-repeat, тому не можу зробити видалення зі списку. Але в мене є гра 2048 з кодом, от я й спробую її прочитати. Читати код корисно. Але ми звісно не намагатимемось розібрати все, а просто візьмемо собі за мету додати до гри штучний інтелект. :)

Код гри

Код взятий з https://github.com/gabrielecirulli/2048.git. Сommit: 6c12037b2a090ed0f1bd7ab1738637810f98da46.

Отож, гра складається з HTML5 веб-сторінки (на що вказує <!DOCTYPE html>), і завантажує наступні скрипти:

  <script src="js/animframe_polyfill.js"></script>
  <script src="js/keyboard_input_manager.js"></script>
  <script src="js/html_actuator.js"></script>
  <script src="js/grid.js"></script>
  <script src="js/tile.js"></script>
  <script src="js/local_score_manager.js"></script>
  <script src="js/game_manager.js"></script>
  <script src="js/application.js"></script>

Читати, очевидно варто починаючи з application.js. Його код короткий, тому вставимо тут повністю:

// Wait till the browser is ready to render the game (avoids glitches)
window.requestAnimationFrame(function () {
  window.game = new GameManager(4, KeyboardInputManager, HTMLActuator, LocalScoreManager);
});

Насправді window.game в оригінальній грі не створювалась, але я її записав щоб мати можливість подосліджувати цей об’єкт за допомогою Firebug.

Додаємо нову клавішу

Клас KeyboardInputManager зберігається в файлі keyboard_input_manager.js і відповідає за ввід (не тільки з клавіатури, а й всіма іншими можливими способами. В тому файлі також можна знайти цікавий словник, що відображає коди клавіш в напрями, і звідки ми можемо дізнатись що 0 – це вверх, 1 – вправо, 2 – вниз і 3 – вліво. Радує те що є також можливість командувати рухами за допомогою клавіш Vim:

  var map = {
    38: 0, // Up
    39: 1, // Right
    40: 2, // Down
    37: 3, // Left
    75: 0, // vim keybindings
    76: 1,
    74: 2,
    72: 3,
    87: 0, // W
    68: 1, // D
    83: 2, // S
    65: 3  // A
  };

Всередині класу GameManager (з файлу game_manager.js), KeyboardInputManager використовується наступним чином:

  this.inputManager = new InputManager;

  ...

  this.inputManager.on("move", this.move.bind(this));
  this.inputManager.on("restart", this.restart.bind(this));
  this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));

Тобто є лише три події, які виконують три методи. Найцікавіший, звісно, метод move, тому що скоріш за все ним, ми змусимо наш штучний інтелект керувати грою. Давайте створимо для його ходу заглушку, і змусимо її виконуватись при натисненні Enter. В keyboard_input_manager.js є обробник натиснення клавіші з наступним кодом:

  document.addEventListener("keydown", function (event) {
      ...
      if (event.which === 32) self.restart.bind(self)(event);

Що означає “при натисненні прогалика – виконати self.restart()“. Додамо туди наступний рядок:

      if (event.which === 13) self.run_ai.bind(self)(event);

Тепер треба додати відповідну функцію:

KeyboardInputManager.prototype.run_ai = function (event) {
  event.preventDefault();
  this.emit("run_ai");
};

Тепер в нашому GameManager можна підписатись на подію:

  this.inputManager.on("run_ai", this.run_ai.bind(this));

Тепер давайте опишемо наш штучний інтелект в функції run_ai:

GameManager.prototype.run_ai = function () {
    this.move(this.random_choice([0, 1, 2, 3]));
};
GameManager.prototype.random_choice = function(items) {
    return items[Math.floor(Math.random() * items.length)];
};

Вона просто робить хід випадковим чином. Дуже непогана стратегія, можна дуже швидко скласти клітинку на 32, тепер можна було б подумати про вдосконалення стратегії.

Копіювання поля

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

Переглядаючи код бачимо що щось схоже на поле створюється наступним кодом:

GameManager.prototype.setup = function () {
  this.grid        = new Grid(this.size);

Ліземо в grid.js.

function Grid(size) {
  this.size = size;
  this.cells = [];
  this.build();
}

// Build a grid of the specified size
Grid.prototype.build = function () {
  for (var x = 0; x < this.size; x++) {
    var row = this.cells[x] = [];

    for (var y = 0; y < this.size; y++) {
      row.push(null);
    }
  }
};

Бачимо що поле має розмір і клітинки. Клітинки це масив масивів null, де null напевне позначає порожні клітинки. І справді, якщо подивитись значення game.grid.cells в Firebug, можна побачити таку структуру:

[[Tile { x=0, y=0, value=2}, null, null, null], [null, null, null, null], [null, null, null, null], [Tile { x=3, y=0, value=2}, null, null, null]]

Якщо продивитись код grid.js трохи далі, можна помітити метод

Grid.prototype.availableCells = function () {
  var cells = [];

  this.eachCell(function (x, y, tile) {
    if (!tile) {
      cells.push({ x: x, y: y });
    }
  });

  return cells;
};

Він повертає нам масив всіх координат які ще не зайняті. Чим їх більше, тим краще, і це ми використаємо для оцінки позиції. Також це показує нам як користуватись методом eachCell, який ми використаємо для того щоб робити копію поля:

Grid.prototype.copy = function () {
    var grid = new Grid(this.size);

    this.eachCell(function (x, y, tile) {
        grid.cells[x][y] = tile;
    });
    return grid;
};

Тепер, функція яка перевіряє скільки буде доступно вільних клітинок на полі, при цьому самого поля не чіпаючи:

GameManager.prototype.try_direction = function(direction) {
        var grid_copy = this.grid.copy();
        this.move(direction);
        var cells_available = this.grid.availableCells().length;
        this.grid = grid_copy;
        return cells_available;
};

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


Filed under: Кодерство Tagged: JavaScript

Must have для сучасних IDE та редакторів

LightTable LogoНаразі у мене є два улюблених редактори для коду: Sublime Text та LightTablevim, хоч любові до гробу не склалося, оскільки я в чистій консолі не так часто працюю, але він теж гарний). Про перший зараз мабуть не знає лише лінивий. У нього багато всяких крутих можливостей для редагування, плюс він дуже круто розширюється завдяки масі доступних плагінів. Але! Все те, що зараз пропонує Саблайм — це необхідний мінімум, без якого я вже не уявляю комфортної роботи, тому на цьому питанні я зупинятись не буду. Набагато цікавіше жити днем завтрашнім і оцінити куди надалі розвиваються редактори. А для того, аби оцінити це, прошу переглянути відео “Inventing on a Principle” (“Винаходячи за принципом”). Його, я впевнений, багато хто вже бачив, тому перепрошую за повторення, можете одразу читати далі. Хто не бачив — обов’язково подивіться. Причому тут його показано не лише для програмування, а й інших сфер як-то радіоелектроніка, обробка відео, тощо. Дуже цікава штука, насолоджуйтесь (до речі, у кого проблеми з англійською — там є російські субтитри):

LightTable concept screenshot Але то все концепт… Гарна ідея, але (мабуть) не тривіальна в реалізації, і невідомо коли ми вже зможемо використати щось подібне в реальній роботі. Чи відомо? Насправді розробники вже можуть помацати перші реалізації цієї ідеї за допомогою LightTable. LightTable наразі єдина робоча реалізація про яку я знаю, тому якщо існують інші — скажіть, я хочу спробувати 😉 Про цей редактор я дізнався суто випадково, коли копав більше інформації про Clojure (власне LT написаний на Clojure і це була перша мова яку він підтримував). Звісно, там все не настільки аж неймовірно як у відео вище, але все ж JavaScript’овий приклад, який зробили з виходом версії 0.4 уже вражає:

Згодом з’явилась ціла серія відео про використання ClojureScript в LightTable в аналогічному стилі. Перше відео тут, далі по списку в Related на Ютюбі.

Звісно, в реальному житті все не настільки райдужно: в LightTable поки нема багатьох можливостей, до яких я вже звик в Sublime Text, тому у більшості випадків я не можу повністю перейти на нього. Плюс справжня real-time розробка наразі є лише для JavaScript, ClojureScript та, в принципі, Clojure. Для останньої та для Python є підтримка трохи простішої, але теж корисної фічі inline evaluation: це REPL прямо у вікні редактора — кльова фіча, я постійно нею користуюсь. Хоча насправді подібна штука не нова і є навіть в Visual Studio 2010 — це інтерактивна консоль для F# (можна подивитись приклад роботи тут).

Must have для сучасних IDE та редакторів

LightTable LogoНаразі у мене є два улюблених редактори для коду: Sublime Text та LightTablevim, хоч любові до гробу не склалося, оскільки я в чистій консолі не так часто працюю, але він теж гарний). Про перший зараз мабуть не знає лише лінивий. У нього багато всяких крутих можливостей для редагування, плюс він дуже круто розширюється завдяки масі доступних плагінів. Але! Все те, що зараз пропонує Саблайм — це необхідний мінімум, без якого я вже не уявляю комфортної роботи, тому на цьому питанні я зупинятись не буду. Набагато цікавіше жити днем завтрашнім і оцінити куди надалі розвиваються редактори. А для того, аби оцінити це, прошу переглянути відео “Inventing on a Principle” (“Винаходячи за принципом”). Його, я впевнений, багато хто вже бачив, тому перепрошую за повторення, можете одразу читати далі. Хто не бачив — обов’язково подивіться. Причому тут його показано не лише для програмування, а й інших сфер як-то радіоелектроніка, обробка відео, тощо. Дуже цікава штука, насолоджуйтесь (до речі, у кого проблеми з англійською — там є російські субтитри):



LightTable concept screenshot Але то все концепт… Гарна ідея, але (мабуть) не тривіальна в реалізації, і невідомо коли ми вже зможемо використати щось подібне в реальній роботі. Чи відомо? Насправді розробники вже можуть помацати перші реалізації цієї ідеї за допомогою LightTable. LightTable наразі єдина робоча реалізація про яку я знаю, тому якщо існують інші — скажіть, я хочу спробувати ;) Про цей редактор я дізнався суто випадково, коли копав більше інформації про Clojure (власне LT написаний на Clojure і це була перша мова яку він підтримував). Звісно, там все не настільки аж неймовірно як у відео вище, але все ж JavaScript’овий приклад, який зробили з виходом версії 0.4 уже вражає:

Згодом з’явилась ціла серія відео про використання ClojureScript в LightTable в аналогічному стилі. Перше відео тут, далі по списку в Related на Ютюбі.

Звісно, в реальному житті все не настільки райдужно: в LightTable поки нема багатьох можливостей, до яких я вже звик в Sublime Text, тому у більшості випадків я не можу повністю перейти на нього. Плюс справжня real-time розробка наразі є лише для JavaScript, ClojureScript та, в принципі, Clojure. Для останньої та для Python є підтримка трохи простішої, але теж корисної фічі inline evaluation: це REPL прямо у вікні редактора — кльова фіча, я постійно нею користуюсь. Хоча насправді подібна штука не нова і є навіть в Visual Studio 2010 — це інтерактивна консоль для F# (можна подивитись приклад роботи тут).

Журнал роботи в Google Sheets та розширення його функцій з JavaScript

Коли я два тижні тому на роботі признався начальнику що вже все зробив, мій начальник вирішив поділитись мною з іншим начальником. Тепер я не можу все зробити, тому що один начальник проводить по дві наради на день на якій мене питають що я зробив, а інший начальник проводить одну нараду на день, на якій теж питають що я зробив. Крім того треба щодня писати звіти, по кожному проекту окремо, бо це впливає на бюджет проектів і на мою зарплатню. І щоб мені було легше пояснити одному начальнику що я сидів на нараді в іншого, та навпаки, я вирішив записувати що роблю протягом дня. Ну звісно виявилось що не багато роблю, але ви коли-небудь пробували записувати що робите? Якщо більше ніж 5 годин корисної роботи на добу – ви мій герой, навчіть мене.

Власне спочатку я хотів завести табличку по методології Pomodoro. Але, виявилось що Pomodoro – це занадто складно коли тебе три наради на день, якщо не рахувати переписок зі співробітниками в Skype. Тому я вирішив просто записувати час початку виконання і час закінчення.

В Google Sheets є дві корисні комбінації клавіш:

  1. Ctrl + ; – вставляє в клітинку дату
  2. Ctrl + Shift + ; – вставляє в клітинку час. В мене чомусь в форматі AM/PM.

Цього було б досить, але рахувати тривалість задач доводиться вручну. Незручно. Якщо є табличка:

A B C D
1 Time started Task Time finished Duration
2 1:32 PM Project A daily stand-up 1:51 PM 0:19

Хочеться щоб колонка D заповнювалась формулою. Але якщо написати в D2 =C2 - A2, воно видасть: “#VALUE!” – Помилка: не число: 1:51 PM. Тому треба використати функції.

Десь я чув фразочку що електронні таблиці – це функціональна мова програмування. Ах. :) Функцій там купа. Клітинок аби зберігати результати їх роботи – теж досить. Але вчити всі ті функції – ну їх.

На щастя Google Docs можна скриптувати за допомогою JavaScript! Ну й правда, не Visual Basic-ом ж користуватись у браузерному застосунку.

Як ми це робимо? Натискаємо “Інструменти” -> “Редактор сценаріїв”. Відкриється онлайновий редактор коду. Вставляємо туди щось таке:

// (c) Salman A     http://stackoverflow.com/a/1788084/816449
function date_diff(date1, date2) {
  if (date2 < date1) {
    date2.setDate(date2.getDate() + 1);
  }
  return date2 - date1;
}

function fmtmsec(msec) {
  var hh = Math.floor(msec / 1000 / 60 / 60);
  msec -= hh * 1000 * 60 * 60;
  var mm = Math.floor(msec / 1000 / 60);
  msec -= mm * 1000 * 60;
  return hh + ':' + mm;
}

function parsetime(cell) {
    var part = cell.match(/(\d+):(\d+)(?: )?(am|pm)?/i);
    var hh = parseInt(part[1], 10);
    var mm = parseInt(part[2], 10);
    var ap = part[3] ? part[3].toUpperCase() : null;
    if (ap === "AM") {
        if (hh == 12) {
            hh = 0;
        }
    }
    if (ap === "PM") {
        if (hh != 12) {
            hh += 12;
        }
    }
    return new Date(2000, 0, 1, hh, mm, 0);
}

function time_diff(arg1, arg2) {
  try {
    arg1 = parsetime(arg1);
    arg2 = parsetime(arg2);
  } catch (e) {
    return '';
  };
  return fmtmsec(date_diff(arg1, arg2));
};

function test() {
  Logger.log(time_diff('9:12 PM', '10:30 PM'));
}

Даємо модулю назву, на зразок Time diff, зберігаємо. В нашій табличці відкриваємо “Інструменти” -> “Менеджер сценаріїв” та переконуємось що наш сценарій там видно.

Тепер, в клітинці D2 можна писати =time_diff(A2;C2). І не поставте кому між аргументами. Буде синтаксична помилка яку я довго шукав в JavaScript, в той час як виявилось що проблема була в записі формули. І це ніби все.

Так просто що мені аж сподобалось.


Filed under: Інструменти, Кодерство, Павутина Tagged: Лайфхаки, JavaScript, робота

Javascript чудовий

Настільки чудовий що дехто навіть мене ревнує. Ну бо логічно, якщо б JavaScript не був таким класним, я б проводив з ним час лише на роботі, а тут займаюсь ним ще й коли іноді ночами не спиться… Останні два тижні на роботі я вже не JavaScript розробник, а DevOps, що є зовсім новою для мене професією, в якій я такий нуб, що повозившись пів дня з 503 помилками сервера я просто змінив для нього користувача з nginx на root і все запрацювало. Звичайно це страшно, але якщо є екстремальне програмування, то повинно ж ще бути екстремальне розгортання, правда? :D Але про те який з мене сисадмін я напишу коли зроблю все правильно, а поки що про JavaScript.

З ним, і трошки з CSS я на дозвіллі вправляюсь на власному сайті http://bunyk.github.io/. І нарешті вже я веб-розробник з сайтом. Бо якось дивно було, в резюме написано що веб-розробник, а крім Python майже нічого не знав…

В JavaScript є свої косяки. Про деякі розповідають у вже класичній презентації WAT!. Хоча node.js в мене деякі штуки показує не так як в тій презентації:

> [] + {}
'[object Object]'
> {} + []
'[object Object]'
> {} + {}
'[object Object][object Object]'

Ну але блін, кому захочеться додавати об’єкти? Якщо ви мали на увазі extend, то така функція є багатьох популярних бібліотеках. Тому якщо про косяки знати – вони не страшні. Достатньо про косяки написано на сторінці JavaScript Garden. Хоча це ж навіть не косяки, а особливості…

Ще хочу показати виступ Дугласа Крокфорда (того що винайшов JSON і написав книжку JavaScript Good Parts). Там він цікаво розповідає про історію LiveScript/JavaScript/JScript/ECMAScript і про те яка нелегка доля цій мові випала. Зокрема, Брендана Ейха змусили взяти синтаксис Java, він хотів написати Scheme. (CoffeeScript проблему з синтаксисом усуває, і це не остання причина використовувати CoffeeScript. Він також усуває косяки, без використання “use strict”;)

The first time I saw JavaScript in 1995, I thought “This is the stupidest thing I ever seen”. And I was pretty confident that I was right. … Five years later … I discovered it has lambdas in it!

Ах, ще з цієї доповіді я дізнався що є така функція як Y комбінатор (рекомендую статтю, вона від того самого дядька який написав illustrated guide to PhD), яка вміє перетворювати рекурсивні функції на нерекурсивні аналоги, і виглядає отак:

var Y = function (F) {
 return (function (x) {
  return F(function (y) { return (x(x))(y);});
  })
        (function (x) {
  return F(function (y) { return (x(x))(y);});
  }) ;
} ;

Я поки що дивлюсь на цю функцію як баран, але думаю незабаром вникну в суть.

Це одна з багатьох речей які зі мною останнім часом відбуваються, але про все розповідати доведеться довго. Тому поки що дивіться мій сайт, коментуйте, ставте лайки, розкажіть друзям, f*&k my repo чи краще submit issue. Пост про nginx, fabric, tar, mako, або систему топологічного сортування залежностей колись буде. Ви лише скажіть що вам цікавіше.


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