Статьи

Zebra: HTML5 Canvas Rich UI Library

Что такое зебра?

Zebra — это библиотека JavaScript, которая следует простым концепциям ООП и реализует богатый набор различных собственных компонентов пользовательского интерфейса. На рынке представлено огромное количество привлекательных и мощных сред веб-интерфейса. Большинство из них привязаны к HTML, DOM и CSS. Они создают пользовательские интерфейсы, окрашивая DOM CSS и манипулируя деревом HTML DOM. Пользовательский интерфейс Zebra отличается. Он не основан на HTML, DOM или CSS. Компоненты Zebra UI реализованы и представлены с нуля в виде ряда виджетов, организованных в иерархии. 

Как Zebra удается создавать и отображать пользовательские интерфейсы в Интернете? Существенная вещь, требуемая абстракцией Зебры, является существованием «подобного Холсту» компонента. Компонент Canvas должен иметь набор графических методов для рисования линий, простых фигур, текста, изображений и улавливать события ввода (клавиатура, мышь и т. Д.). Например, Java AWT / SWING, Eclipse SWT, .NET или другие платформы будут поставлять «Canvas-like» компоненты. Но новый стандарт HTML5 включает в себя элемент «Canvas». Этот элемент поддерживается большинством современных браузеров и делает возможным и разумным «перетянуть» Zebra UI в веб-контекст.

Посмотреть демо Zebra http://zebra.gravitysoft.org


В приведенной ниже таблице перечислены наиболее важные компоненты пользовательского интерфейса Zebra, представление менеджеров и т. Д. Компоненты, отмеченные оранжевым фоном, все еще находятся в разработке:

Конвертер Zebra Java в JavaScript выходит из контекста в этой статье, тем не менее он играет ключевую роль в переносе компонентов пользовательского интерфейса на основе Java в Интернет. В демонстрационных целях доступна слегка устаревшая версия конвертера Java в JavaScript: http://j2js.gravitysoft.org

Zebra JavaScript Easy OOP концепция 

Привлекательная, простая в использовании и понятная модель программирования очень важна в контексте наличия поддерживаемого, расширяемого и элегантного кода. Это одна из болезненных проблем в веб-разработке. Zebra представляет простые концепции ООП в качестве основы. ~ 10.5kb кода Zebra помогает сделать следующее:

Для получения дополнительной информации о Zebra OOP см. Шпаргалку: шпаргалка Zebra easy OOP concept

Приложение Zebra «Hello WEB»

Демонстрация Zebra JavaScript показывает отступ во внутреннем окне с заголовком «Hello web». Окно открывается нажатием кнопки:

// create canvas and store root panel in local variable
var c = new zCanvas(html5Canvas), r = c.root;

// create button
var b = new Button("Hello WEB");

// set border layout manager  
r.setLayout(new BorderLayout());

// add button to center of root panel
r.add(Layout.CENTER, b);

// register the button event listener that opens external 
// window every time the button has been pressed 
b._(function() {  
    var w = new Window("Hello WEB");
    w.setSize(200,200);
    w.show();
});

Возможности пользовательского интерфейса Zebra с помощью фрагментов кода JavaScript

Дизайн компонентов Zebra UI следует подходам, аналогичным традиционным Java AWT / SWING, .NET и Eclipse SWT. Компоненты пользовательского интерфейса организованы в виде иерархии, в которой одни компоненты располагаются на других. Но Зебра делает многое гораздо быстрее и проще. Ниже приведены некоторые возможности пользовательского интерфейса Zebra с фрагментами кода:

  • Составные компоненты. Компоненты пользовательского интерфейса Zebra часто создаются в виде комбинации нескольких других компонентов, расположенных на панели. Например, компонент «Кнопка» — это панель, в которой в качестве метки хранится дочерний компонент. По умолчанию заголовок «Метка», но разработчики могут установить другие компоненты пользовательского интерфейса в качестве метки кнопки. Посмотрите на фрагменты ниже:
    // by default button uses label component as its content
    var button = new Button("Label");
    
    // set image as the button label
    var button = new Button(new ImagePan("b.png"));
    
    // set image+label as the button content. The image+label is also
    // compound component that consists of image and label
    var bContent = new Panel(new FlowLayout());
    bContent.add(new ImagePan());
    bContent.add(new Label());
    var button = new Button(bContent);
    

    Компонент пользовательского интерфейса BorderPan является еще одним примером составного компонента. Он состоит из ярлыка и панели содержимого. Посмотрите на фрагменты ниже:

    // border panel uses simple "Label" as its title by default
    var bp = new BorderPanel("Label", new Panel());
    
    // border panel uses another border panel as its title 
    var bp = new BorderPanel(new BorderPan("Label"), new Panel());
    
    // border panel uses "Checkbox" as its title
    var bp = new BorderPanel(new Checkbox("Check me"), new Panel());
    
  • Полный контроль над рендерингом пользовательского интерфейса . Рисование компонентов Zebra UI полностью в руках разработчиков. Zebra вызывает методы компонента пользовательского интерфейса «paint», «update», «paintOnTop» с графическим контекстом в качестве входного аргумента. Эти методы формируют грань компонента пользовательского интерфейса. Пропущенный графический контекст дает разработчикам ряд элементарных методов для рисования и заливки примитивных фигур, рисования текста и изображений.

    Метод «paint» определяет компонент «face» пользовательского интерфейса:

    // create inner class instance with redefined component "face" 
    var myEyesCandyComponent = new Panel([
        function paint(g) {
            // paint what ever you want using passed graphical context
            g.drawLine(...);
            g.drawRect(...);
            g.fillArc(...);
        }
    ]);
    

    Метод «update» формирует фон компонента:

    // create inner class instance and override background 
    // rendering with a custom implementation
    var myEyesCandyComponent = new Panel([
        function update(g) {
           ...
        }
    ]);
    

    Метод paintOnTop может использоваться, например, для визуализации индикатора фокуса над компонентом «лицо»:

    // render rectangle around component if the component holds focus
    var myEyesCandyComponent = new Panel([
        function paintOnTop(g) {
    	if (this.hasFocus()) g.drawRect(0,0, this.width, this.height);
        }
    ]);
    

    Менеджер рисования Zebra позаботится о том, чтобы вызвать перерисовку недействительных «грязных» областей. Компоненты пользовательского интерфейса предназначены для того, чтобы исключить прямое выполнение перерисовки метода. Но компоненты пользовательского интерфейса должны вызывать thr «repaint ([x, y, w, h])» каждый раз, когда появляется новая грязная область. Выполнение метода «repaint» запускает менеджер рисования для пересчета текущей грязной области и планирования перерисовки, когда это возможно:

    var MyCustomComponent = Class(Panel, [
         function setBorderColor(c) {
              this.color = c;
              this.repaint(); // inform paint manager the component 
                                    // has to be  completely re-painted
         } 
    ]);
    
  • Аккуратная обработка событий. Когда это возможно, обработка событий Zebra следует декларативному шаблону (см. Следующую функциональную схему). Это позволяет разработчикам избегать регистрации слушателей и упрощает концепцию обработки событий. Чтобы поймать событие: 

    • Выразите намерение получить желаемый тип события путем наследования соответствующего интерфейса. Интерфейс похож на маркер.
    • Реализуйте функцию (и) для обработки желаемого события.

    Например, представьте пользовательский компонент, который должен обрабатывать события мыши. Выразите намерение, реализовав интерфейс MouseListener:

    // let Zebra know that the component wants getting mouse 
    // events by implementing"MouseListener" interface
    var MyComponent = new Class(Panel, MouseListener,  []);
    

    Предположим, что «кнопка мыши нажата» и «курсор мыши вошел в компонент» должны обрабатываться типы событий. Для этого объявите следующие функции соответственно:

    var MyComponent = new Class(Panel, MouseListener, [
        function mousePressed(e) {
    	// handle mouse pressed event here
        },
                                                        
        function mouseEntered(e) {
            // handle mouse entered event here
        }
    ]);
    
    • Глобальная обработка событий. Специальный менеджер событий Zebra отслеживает все события, произошедшие для всех созданных экземпляров компонентов пользовательского интерфейса. Менеджер может быть использован для регистрации глобальных слушателей событий, которые получают все события данного типа. Например, прослушивание событий фокуса во всем мире может быть сделано следующим образом:
      // instantiate "FocusListener" interface to express that focus 
      // events have to be catched
      zebra.ui.events.addListener(new FocusListener([
           function focusLost(e) { ... },
           function focusGained(e) { ... }
      ]));
      
    • Поймать дочерние компоненты событий. Компонент «Родительский интерфейс» может прослушивать входные события, которые произошли в его дочерних элементах, реализуя интерфейс «ChildrenListener» и добавляя соответствующие методы следующим образом:
      // implements "ChildrenListener" interface to express intention 
      // to get children events 
      var MyComponent = new Class(Panel, ChildrenListener, [
          function childInputEvent(e){
              // handle children events here 
          }
      ]);
      
    • Композитный компонент (прозрачные события). Часто составные компоненты пользовательского интерфейса должны предотвращать получение дочерними компонентами каких-либо событий. Дочерние компоненты становятся прозрачными для событий. Это можно сделать, реализовав интерфейс Composite и добавив метод catchInput. Метод должен возвращать «true», если переданный в качестве аргумента child должен быть прозрачным по событию. Например:
      var MyComponent = new Class(Panel, Composite, [
          function catchInput(kid){
              // return true if the given kid has to be event transparent
              return true;
          }
      ]);
      
  • Декларативная картина. Msgstr «Сначала наследуйте интерфейс, чтобы выразить намерение что-то сделать, а затем реализуйте требуемый метод (ы)». Такой подход позволяет Zebra отделить различные функциональные части друг от друга. Расширение в этом контексте означает добавление новых декларативных шаблонов вместо перегрузки классов пользовательского интерфейса Zebra новым кодом и API. Например, представьте, что нам нужно менять тип курсора мыши каждый раз, когда указатели мыши входят в компонент пользовательского интерфейса. Компоненты Zebra UI не знают, как управлять типом курсора мыши. Это менеджер курсора («zebra.ui.cursor»), который делает это:
    // inherits "CursorInfo" interface to let cursor manager know 
    // the component controls mouse cursor
    var p = new Panel(CursorInfo, [
        // declare method that returns mouse cursor type for the component
        function getCursorType(x, y){
            return Cursor.WAIT;  
        }
    ]);
    
  • Операции преобразования HTML5 Canvas могут быть применены к пользовательскому интерфейсу. Поворот, увеличение, уменьшение и другие графические эффекты преобразования могут быть применены к Zebra UI:
    // zoom UI in 1.3 times vertically 
    // and horizontally
     zCanvas.scale(1.3, 1.3);
     // rotate
     zCanvas.rotate(0.3);
     ...
     // set back to initial stat
     zCanvas.scale(null);
     zCanvas.rotate(null, null);
    
  • Посмотрите и почувствуйте настройку. Многие визуальные характеристики компонентов Zebra UI определяются специальным файлом свойств. Если файл свойств недостаточно настраиваем, можно реализовать класс мастера интерфейса пользователя. Экземпляр класса уведомляется обо всех созданных экземплярах компонентов пользовательского интерфейса путем вызова метода «настройки». Это помогает настроить внешний вид компонентов пользовательского интерфейса «на лету». Например, давайте определим собственный класс мастера, чтобы закрасить все компоненты меток красным фоном:
    // declare custom Wizard class 
    var MyCustomWizard = Class(Wizard,  [
        // the method is called every time a new component has been 
        // instantiated
        function customize(id, comp) { 
             // customize just instantiated label component background
             if (id == Wizard.LABEL) comp.setBackground(Fill.red);
        } 
    ]);
    

    Затем настройте ваш мастер с помощью файла свойств следующим образом:

    ...
    # specify wizard to be used for UI customization
    wizard = MyCustomWizard()
    
  • Многоуровневая архитектура. Zebra Canvas — корневая панель, состоящая из нескольких слоев. Слои представляют собой стандартный Zebra UI «Панель», который растягивается по всей поверхности Canvas. Зебра держит слои как стек. Каждый раз, когда происходит событие, менеджер событий Zebra «спрашивает» (начиная сверху вниз), кто хочет взять на себя управление. Первый встреченный слой, который захватывает управление, выбран в качестве цели. Картинка ниже объясняет это:

    Давайте разработаем слой, который замораживает (блокирует любое взаимодействие) и размораживает компоненты пользовательского интерфейса, нажимая комбинацию клавиш «CTRL + SHIFT + ALT». Замораживание обозначается затемнением компонентов пользовательского интерфейса:

    // declare custom layer class that inherits "BaseLayer" class
        var Freezer = Class(BaseLayer, [
    	function () {
                this.$super("FREEZER"); // call super with unique layer ID
                this.isActive = false;
                // set background to be 100% transparent
                this.setBackground(null);
           },
                                    
           function layerKeyPressed(code, mask) {
                var rm = KeyEvent.CTRL + KeyEvent.SHIFT + KeyEvent.ALT;
                if ((rm & mask) == rm) {
                     // CTRL+SHIFT+ALT keys combination has been pressed   
                     if (this.isActive) this.setBackground(null);
                     else  this.setBackground(new Fill(255,255,255, 0.7));
                     this.isActive = ! this.isActive;
                 }
           },
                  
           // methods below indicate if the layer is in active state (take control)                   
           function isLayerActive(){ return this.isActive;},
           function isLayerActiveAt(x,y){return this.isActive; }
    ]);
    ...
    // add the layer to zebra canvas
    zCanvas.add(new Freezer());
    

    Результат работы слоя продемонстрирован ниже:

    Не замороженный интерфейс Замороженный интерфейс
                   
  • Управление раскладкой. Макет определяет правило, которое говорит, как формировать количество дочерних компонентов на данной панели. Позиционирование на основе правил намного лучше, чем использование абсолютных местоположений и фиксированного размера. Полученные преимущества такие же, как «векторная или пиксельная графика». Менеджеры компоновки Zebra не зависят от пакета пользовательского интерфейса Zebra и могут использоваться повторно для компоновки других объектов, например элементов HTML. Давайте посмотрим, как, например, диагональные макеты могут быть реализованы. Пользовательский менеджер компоновки размещает дочерние компоненты, выравнивая его верхние левые углы по диагонали:
    // declare diagonal layout manager
    var DiagonalLayout = Class(Layout, [
         // "layout" method positions and shapes visible 
         // children of target  component
         function layout(target) {
              var x = 0, y = 0;
              for (var i=0; i<target.kids.length; i++) {
                   var kid = target.kids[i];  
                   if (kid.isVisible) { 
                         kid.setLocation(x, y); 
                         kid.toPreferredSize();
                         x += kid.width;
                         y += kid.height;
                    }
               }                              
           },
                                        
           function calcPreferredSize(target) {
                ...
           }
    ]);  
    
    // setup DiagonalLayout manager for a panel and add
    // three children labels
    var p = new Panel(new DiagonalLayout());
    p.add(new Label("Label1"));
    p.add(new Label("Label2"));
    p.add(new Label("Label3"));
    
  • Фокус, события, краски и другие менеджеры. Zebra делегирует ключевые функциональные части так называемым классам менеджера. 
    • Менеджер рисования призван определить стратегию рисования 
    • Менеджер событий решает, как данное событие должно быть распределено по компонентам и модулям пользовательского интерфейса. 
    • Менеджер фокуса знает, как переключить фокус между компонентами.

    Все перечисленные выше менеджеры являются относительно простыми классами Zebra, которые могут быть переопределены, когда это необходимо. Разработчики могут реализовать новый диспетчер фокусировки, который вводит новую стратегию навигации фокусировки, или они могут создать более эффективный и быстрый диспетчер рисования.

  • Представления и визуализация как простейшие визуальные элементы многократного использования «кирпичи». Компоненты пользовательского интерфейса используют множество визуальных элементов для создания своего внешнего вида, такого как фон, границы и т. Д. Zebra объявляет специальные классы («Вид» и «Визуализация»), которые будут использоваться для реализации «кирпичиков». Zebra предоставляет ряд важных готовых к использованию видов и рендеров. Взгляните на несколько фрагментов ниже:
    var p = new Panel();
    // set gray, solid 2px border 
    p.setBorder(new SimpleBorder(SimpleBorder.SOLID, Color.gray, 2));
    
    // set "Gradient" background
    p.setBackground(new Gradient(Color.gray, Color.black));
    
    // set image as the component background
    p.setBackground(new ImgRender(“bg.png”));
    

// set custom diagonal stripped lines background 
p.setBackground(new View([
   function paint(g, x, y, w, h, target) {
      var s = 8;
      g.setColor(Color.gray);
      for(var i=0; i < 2*w/s; i++) {
        g.drawLine(x+s*i, y, x, y+s*i);  
     }
   }
]));

Резюме зебры

Простые концепции ООП, богатый набор компонентов пользовательского интерфейса, полный контроль над визуализацией пользовательского интерфейса, графические эффекты, настраиваемый внешний вид, разработка программного обеспечения для Интернета, Model-View-Controller, без манипуляций с DOM, небольшая и быстрая, многоплатформенная, и с открытым исходным кодом. Это основные характеристики, которые определяют Зебра.