Các thành phần của HTML5: Thành phần Ad-hoc, Phần 1

Tìm hiểu mô hình thành phần HTML5 và bắt đầu thực hiện thành phần ad-hoc

Bài viết này giới thiệu một phần ngắn trong loạt bài của David Geary triển khai về các thành phần của HTML5. Trong bài viết này giúp chúng ta có được kiến thức tổng quan về các thành phần của HTML5 và tìm hiểu cách làm thế nào để thực hiện một thành phần Slider (công cụ thanh trượt) ngay từ ban đầu.

David Geary, Tác giả và diễn giả, Clarity Training, Inc.

David GearyDavid Geary, tác giả của quyển sách Core HTML5 Canvas, cũng là đồng sáng lập của Nhóm người dùng HTML5 Denver và là tác giả của 8 cuốn sách Java, bao gồm cả những cuốn sách bán chạy nhất về Swing và JavaServer Faces. David là một diễn giả thường xuyên tại các hội nghị, bao gồm JavaOne, Devoxx, Loop Strange, NDC và OSCON và ông đã ba lần đạt danh hiệu JavaOne Rock Star (diễn giả hàng đầu tại hội nghị JavaOne). Ông đã viết loạt bài Lập trình game 2D trên HTML5 2D, JSF 2 fu, và GWT fu cho developerWorks.



05 09 2013

Giới thiệu về loạt bài

Một mô hình thành phần giao diện người dùng cho HTML5 vẫn đang phát triển. Trong loạt bài này, chuyên gia HTML5 David Geary hướng dẫn bạn tự tạo thành phần ad-hoc HTML5 với công nghệ có sẵn và cách tận dụng các đặc tả kỹ thuật để định nghĩa một hệ thống HTML5 đúng nghĩa.

Mô hình thành phần là một yếu tố quan trọng khi lập trình cho bất kỳ nền tảng nào vì nó cung cấp một tập hợp tiêu chuẩn các yếu tố giao diện người dùng và cơ sở hạ tầng để xây dựng tốt hơn.

HTML5 là một công nghệ mới với tập hợp các thông số kỹ thuật, thậm chí là tốt hơn nhằm mục đích để chuẩn hóa các thành phần của HTML5 và tích hợp nó với các thành phần khác. Mô hình thành phần HTML5 hiện đang được xác định bởi ba thông số kỹ thuật:

  • "Giới thiệu về các thành phần Web"
  • "Shadow DOM"
  • "Các mẫu HTML"

Các chức năng trong ba thông số kỹ thuật liên quan đến việc bao đóng thành phần của cây DOM (Shadow DOM), tạo ra các thẻ tùy chỉnh cho các thành phần mà tác giả có thể sử dụng trong các trang HTML của họ (các phần tử HTML tùy biến), khai báo Shadow DOMs cụ thể và điểm thêm vào (các mẫu HTML). (Đọc đoạn "Đặc tả thành phần HTML5" để biết thêm chi tiết.)

Đặc tả thành phần HTML5

Bài "Giới thiệu về các thành phần Web" mô tả tổng quan về Web Components và được dùng để sinh ra các đặc tả, như các đặc tả "Shadow DOM" và "Các mẫu HTML".

Đặc tả "Shadow DOM" là một dự thảo của World Wide Web Consortium (W3C), nó được xem là một phần của HTML5. Shadow DOM cung cấp cho các nhà phát triển quyền đóng gói các thành phần mà họ thực hiện, giống như cách mà các nhà cung cấp trình duyệt từ lâu đã có thể đóng gói các phần tử cấp thấp trong các phần tử video và phạm vi đầu vào.

Đặc tả "Các mẫu HTML" vẫn chưa có bản dự thảo, nhưng nó đã được chia sẻ ý tưởng từ các nhà phát triển và có tiềm năng hình thành. Các mẫu cho phép bạn khai báo Shadow DOMs có điểm thêm vào nơi bạn có thể thêm các phần tử được chọn với các bộ lựa chọn CSS.

Xem phần Tài nguyên để tìm đường dẫn đến mỗi đặc tả.

Nhưng để thực hiện các thành phần lần đầu tiên, bạn cần nhiều kỹ năng khác nhau bao gồm khả năng đồ họa, lớp các phần tử HTML để hỗ trợ các tương tác, hỗ trợ các bộ lắng nghe sự kiện. Loạt bài này bao gồm tất cả các khía cạnh của việc phát triển thành phần HTML5:

  • Những thành phần Ad-hoc
  • Shadow DOM, các mẫu, và các phần tử tùy chỉnh
  • Mozilla's X-Tag

Trong bài viết này và các bài tiếp theo, chúng ta sẽ xem xét cách để thực hiện những thành phần ad-hoc HTML5 từ đầu, mà không cần bất kỳ sự hỗ trợ từ các đặc tả kỹ thuật mới. Sau đó sẽ khám phá những chi tiết kỹ thuật và chỉ cho bạn cách để kết hợp Shadow DOM, các yếu tố tùy chỉnh và các mẫu xây dựng bản ghi HTLM5 của bạn.

Cụ thể trong bài viết này, chúng ta sẽ học cách:

  • Thực hiện những thành phần ad-hoc HTML5
  • Vẽ những hình ảnh sắc sảo với phần tử canvas
  • Sử dụng những phần tử lớp canvas để thực hiện những hiệu ứng đặc biệt
  • Xử lý những thao tác kéo thả thời gian thực với HTML

Xây dựng một thành phần HTML5 từ những thành phần khác

Hình 1 hiển thị thành phần xử lý ảnh được xây dựng từ những thành phần cơ bản chung như: biểu tượng, một thanh công cụ, Slider, và vùng hiển thị ảnh.

Hình 1. Một thành phần xử lý ảnh
Ảnh chụp hai thành phần của trình xem ảnh: Ảnh trên sử dụng thanh trượt thay đổi kích cỡ; ảnh dưới hiển thị hình ảnh sau khi xoay.

Ba biểu tượng trên thanh công cụ — điều chỉnh kích thước, xoay, và độ sáng — được tích hợp với Slider. Khi nhấn vào một trong ba biểu tượng đó, phần xử lý ảnh hiểu thị ra thanh công cụ và một loạt các nút liên quan nằm phía dưới thanh công cụ. Ảnh phía trên của Hình 1 minh họa sử dụng Slider để điều chỉnh kích thước; ảnh dưới hiển thị hình ảnh sau khi xoay với thanh xoay.


Thành phần Slider

Những Slider bao gồm một thanh trượt và một nút điều chỉnh; thay đổi giá trị Slider bằng cách di duyển nút chạy dài trên thanh trượt. Vị trí của nút xác định giá trị Slider (hay nếu lập trình thiết lập giá trị và vẽ lại Slider). Giá trị đó — là một số nằm giữa 0.0 và 1.0 — miêu tả phần trăm của thanh trượt nằm bên trái nút; Ví dụ: nếu 3/4 của thanh trượt nằm bên trái nút thì giá trị của thanh là 0.75.

Hình 2 hiển thị một ứng dụng đơn giản biểu diễn cách sử dụng Slider. Ngoài Slider, ứng dụng còn bao gồm 2 nút: để di chuyển nút điều chỉnh sang phải (+) hay trái (-). Ứng dụng cũng đưa ra giá trị hiện tại của Slider nằm phía dưới Slider. Xem phần Tài nguyên để tìm đường dẫn chạy ứng dụng; bạn cũng có thể tải về mã nguồn.

Hình 2. Một slider
Ảnh chụp thanh trượt

Người dùng có thể di chuyển nút điều chỉnh của Slider bằng 3 cách:

  • Nhấn một trong các nút tăng (+) hay nút giảm (-) giá trị cho mỗi lần là 10%.
  • Kéo nút điều chỉnh.
  • Nhấn lên thanh trượt, bên ngoài nút điều chỉnh, để di chuyển vị trí trung tâm của nút đến vị trí nhấn chuột.

Khi giá trị Slider được cài đặt bằng chương trình — khi nhấn nút tăng (+) hay giảm (-) hay nhấn trên thanh trượt của Slider bên ngoài nút điều chỉnh — Sự di chuyển của nút nhờ vào quá trình chuyển đổi CSS với việc di chuyển dứt khoát, chầm chậm của nút khi nó tiếp cận đến điểm cuối cùng. Thành phần Slider cài đặt những thuộc tính chuyển đổi trong JavaScript.

Để sử dụng Slider, cần khởi tạo và gắn nó với một DOM hiện có, được hiển thị trong Liệt kê 1.

Liệt kê 1. Tạo một Slider
var slider = new COREHTML5.Slider( // All of the following arguments are optional
   'navy',           // Stroke color
   'cornflowerblue', // Fill color
   0.5,              // Initial slider value
   500);             // Knob animation duration in milliseconds
...

slider.appendTo('someDiv');  // Appends the slider to a DOM element with the ID someDiv

Phương thức appendTo() của Slider điều chỉnh kích thước của Slider mở rộng hay co lại tương thích với phần tử Slider được đính kèm.

Tại sao không sử dụng một phạm vi đầu vào?

Có hai lý do để chọn thực hiện một thành phần Slider mặc dù HTML cung cấp sẵn một phạm vi đầu vào. Đầu tiên, có thể bạn muốn chắc chắn rằng các trình duyệt đều hiển thị và cảm nhận như nhau, đó là trường hợp thành phần xử lý ảnh được hiển thị trong Hình 1. Thứ hai là các trình duyệt như Firefox tập trung vào việc nhập văn bản để đại diện cho một phạm vi. Trong nhiều trường hợp, điều đó vẫn chưa đủ.

Những tính năng của Slider:

  • Đính kèm những phần tử DOM với một phương thức appendTo()
  • Tự động điều chỉnh kích thước để đưa phần tử DOM vào Slider được đính kèm
  • Đăng ký thay đổi trình lắng nghe sự kiện với phương thức addChangeListener()
  • Gióng các sự kiện thay đổi để thay đổi các trình lắng nghe khi di chuyển nút điều chỉnh trên Slider
  • Làm hiệu ứng động cho nút điều chỉnh với CSS khi người dùng nhấn vào thanh trượt

Các Slider là thể hiện của COREHTML5.Slider để tránh bị trùng namespace. Không khó để tưởng tượng rằng có người nào đó thực hiện một Slider với một cái tên như Slider, mà sẽ thay thế các đối tượng toàn cục với một tên giống nhau. Điều này là không chắc chắn, tuy nhiên bất kỳ ai cũng sẽ đưa ra COREHTML5.Slider của chính mình.

Những đối số của hàm khởi tạo COREHTML5.Slider là tùy chọn; tất cả đều có giá trị mặc định phù hợp. Bảng 1 liệt kê những phương thức COREHTML5.Slider chính.

Bảng 1. Các phương thức chính của Slider
Phương thứcMô tả
appendTo(elementId)Thêm phần tử DOM của Slider vào phần tử có ID phù hợp với giá trị thông qua phương thức này.
addChangeListener(listenerFunction)Thêm một hàm lắng nghe cho Slider. Khi nút điều chỉnh của Slider thay đổi vị trí, Slider gióng lên một sự kiện để thay đổi trình lắng nghe.
draw()Vẽ thanh trượt và nút điều chỉnh của Slider.
erase()Xóa Slider.
redraw()Xóa và vẽ lại Slider.

Bảng 1 Liệt kê những phương thức bên ngoài mà nhà phát triển sử dụng để thao tác một Slider. Đối tượng COREHTML5.Slider cũng có nhiều phương thức sử dụng bên trong như initializeStrokeAndFillStyles()createKnobCanvas().

Những nhà phát triển truy cập giá trị của Slider thông qua thuộc tính knobPercent.


Sử dụng Slider

Liệt kê 2 hiển thị mã HTML cho ứng dụng được trình bày trong Hình 2.

Liệt kê 2. Mã HTML cho Slider
<!DOCTYPE html>
<html>
   <head>
      <title>Ad hoc components</title>

      <style>
         body {
            background: rgb(240,240,240);
         }
         
         #title {
            font: 18px Arial;
         }

         #slider-component {
            width: 400px;
            text-align: center;
         }

         #buttons {
            display: inline;
            font: 14px Arial;
         }
         
         #readout {
            margin-left: 25%;
            color: blue;
            font: 18px Arial;
            text-shadow: 2px 2px 2px rgb(255,255,255);
         }
         
         #slider {
            width: 75%;
            height: 30px;
            float: right;
         }

         .slider-button {
            background: rgba(100, 100, 100, 0.2);
            font: 24px Arial;
            font-weight: 1;
            border-radius: 4px;
            border: 1px solid rgba(100, 100, 180, 0.7);
            background: rgba(255, 255, 0, 0.2);
            box-shadow: 1px 1px 2px rgba(0,0,0,0.5);
            cursor: pointer;
            margin: 0px;
         }
      </style>
   </head>
   
   <body>
      <div id='title'>A custom slider</div>

      <p>
         <div id='slider-component'>
            <div id='controls'>
              <div id='buttons'>
                 <input type='button' class='slider-button'
                          id='minus-button' value='&ndash;'/>

                 <input type='button' class='slider-button' 
                          id='plus-button' value='&plus;'/>
              </div>

              <div id='slider'></div>
            </div>

            <div id='readout'>0</div>
         </div>
      </p>
   </body>

   <script type="text/javascript" src="lib/slider.js"></script>
   <script type="text/javascript" src="sliderExample.js"></script>

</html>

Mã HTML trong Liệt kê 2 tạo ra mô hình cây DOM được hiển thị ở Hình 3.

Hình 3. Mô hình cây DOM mẫu cho Slider
Cấu trúc DOM của thanh trượt mẫu, chứa một thẻ DIV với ID là slider-component, thẻ này chứa 2 thẻ DIV khác, 1 có ID là controls và 1 có ID là buttons. Thẻ DIV buttons có 2 thành phần elements, mỗi element có type là button và class là slider-button. Một button có ID là minus-button và button còn lại có ID là plus-button. Cuối cùng, thẻ DIV slider-component chứa 1 DIV rỗng có ID là slider.

Mã HTML và CSS trong Liệt kê 2 rất đơn giản. Mã HTML tham chiếu đến 2 đoạn script (kịch bản), một cho Slider và một cho chính ứng dụng. Mã script của ứng dụng được hiển thị trong Liệt kê 3.

Liệt kê 3. JavaScript của Slider mẫu
var slider = new COREHTML5.Slider('black', 'cornflowerblue', 0),
    readoutElement = document.getElementById('readout');

document.getElementById('minus-button').onclick = function (e) {
   slider.knobPercent -= 0.1;
   slider.redraw(); 
   updateReadout();
}

document.getElementById('plus-button').onclick = function (e) {
   slider.knobPercent += 0.1; 
   slider.redraw(); 
   updateReadout();
}

function updateReadout() {
   if (readoutElement)
      readoutElement.innerHTML = slider.knobPercent.toFixed(2);
}

slider.addChangeListener(updateReadout);

slider.appendTo('slider');
slider.draw();

Mở đầu mã JavaScript trong Liệt kê 3, ứng dụng tạo ra Slider với kiểu nét đen (black stroke style), tô màu xanh hoa bắp (cornflower), và giá trị ban đầu là 0. ứng dụng gắn thêm một thanh trượt vào phần tử DOM với ID là slider. Ở phần giữa, mã JavaScript định nghĩa 3 trình xử lý sự kiện (event handlers), chúng xử lý những nút nhấn và những thay đổi giá trị của Slider.

Ứng dụng thêm trình xử lý sự kiện onclick tới nút tăng (+) và giảm (-), chúng điều chỉnh giá trị của Slider (knobPercent), vẽ lại Slider, và cập nhật hiển thị.

Ứng dụng cũng thêm một bộ lắng nghe thay đổi đến Slider, nó cập nhật màn hình ứng dụng tương ứng với giá trị mới của Slider. Những thành phần thường cung cấp một cơ chế cho đăng ký những bộ lắng nghe sự kiện và chuyển những sự kiện đến bộ lắng nghe sự kiện thích hợp, và thành phần Slider cũng không ngoại lệ.

Bây giờ bạn đã biết cách sử dụng một Slider, hãy xem xét việc thực hiện các thành phần của nó.


Tạo và khởi tạo Slider

Liệt kê 4 hiển thị đoạn mã JavaScript cho hàm khởi tạo của Slider.

Liệt kê 4. Hàm khởi tạo của Slider
COREHTML5 = COREHTML5 || {};

COREHTML5.Slider = function(strokeStyle, fillStyle,
                            knobPercent, knobAnimationDuration) {
   knobPercent = knobPercent || 0;
   knobAnimationDuration = knobAnimationDuration || 1000; // milliseconds

   this.railCanvas = document.createElement('canvas');
   this.railContext = this.railCanvas.getContext('2d');
   this.changeEventListeners = [];

   this.initializeConstants();
   this.initializeStrokeAndFillStyles(strokeStyle, fillStyle);
   this.initializeKnob(knobPercent, knobAnimationDuration);

   this.createDOMTree();
   this.addMouseListeners();
   this.addKnobTransitionListeners();

   return this;
}

Dòng đầu tiên của Liệt kê 4 sử dụng một câu lệnh JavaScript chung để đảm bảo rằng một đối tượng là toàn cục — trong trường hợp này là COREHTML5—. (nếu không tồn tại, sẽ được gán cho chính nó, nếu không nó sẽ được gán cho một đối tượng rỗng.)

Hàm khởi tạo của COREHTML5.Slider có bốn đối số tùy chọn: màu viền (stroke color), màu nền (fill color), giá trị ban đầu của Slider (initial slider value), và thời gian hoạt cảnh của nút điều chỉnh tính theo phần ngàn giây (knob animation duration in milliseconds). Biến knobPercent đại diện cho giá trị của thanh trượt.

Hàm khởi tạo tạo một canvas —railCanvas— chứa thanh trượt của Slider. Nó cũng tạo một canvas thứ hai —knobCanvas— với createKnobCanvas() (hiển thị trong Liệt kê 5), được gọi trong Liệt kê 4 bởi initializeKnob(). Cuối cùng, hàm khởi tạo tạo cây DOM của Slider và thêm vào các bộ lắng nghe.

Ba phương thức đầu tiên được gọi bởi hàm khởi tạo của Slider —initializeConstants(), initializeStrokeAndFillStyles(), và initializeKnob()— được thể hiện trong Liệt kê 5.

Liệt kê 5. Các phương thức khởi tạo của Slider
COREHTML5.Slider.prototype = {
   initializeConstants: function () {
      this.SHADOW_COLOR = 'rgba(100, 100, 100, 0.4)';
      this.SHADOW_OFFSET_X = 3;
      this.SHADOW_OFFSET_Y = 3;
      this.SHADOW_BLUR = 4;

      this.KNOB_SHADOW_COLOR = 'rgba(255,255,0,0.8)';
      this.KNOB_SHADOW_OFFSET_X = 1;
      this.KNOB_SHADOW_OFFSET_Y = 1;
      this.KNOB_SHADOW_BLUR = 0;

      this.KNOB_FILL_STYLE = 'rgba(255, 255, 255, 0.45)';
      this.KNOB_STROKE_STYLE = 'rgb(0, 0, 80)';

      this.HORIZONTAL_MARGIN = 2.5 * this.SHADOW_OFFSET_X;

      this.VERTICAL_MARGIN = 2.5 * this.SHADOW_OFFSET_Y;

      this.DEFAULT_STROKE_STYLE = 'gray';
      this.DEFAULT_FILL_STYLE = 'skyblue';
   },

   initializeStrokeAndFillStyles: function(strokeStyle, fillStyle) {
      this.strokeStyle = strokeStyle ? strokeStyle : this.DEFAULT_STROKE_STYLE;
      this.fillStyle = fillStyle ? fillStyle : this.DEFAULT_FILL_STYLE;
   },

   initializeKnob: function (knobPercent, knobAnimationDuration) {
      this.animatingKnob = false;
      this.draggingKnob = false;

      this.knobPercent = knobPercent;
      this.knobAnimationDuration = knobAnimationDuration;

      this.createKnobCanvas();
   },

   createKnobCanvas: function() {
      this.knobCanvas = document.createElement('canvas');
      this.knobContext = this.knobCanvas.getContext('2d');

      this.knobCanvas.style.position = "absolute";
      this.knobCanvas.style.marginLeft = "0px";
      this.knobCanvas.style.marginTop = "1px";
      this.knobCanvas.style.zIndex = "1";
      this.knobCanvas.style.cursor = "crosshair";
      ...

   },
   ...
};

Các canvas riêng biệt cho thanh trượt và nút điều chỉnh

Thành phần Slider sử dụng các canvas riêng biệt cho thanh trượt và nút điều chỉnh để sử dụng CSS tạo hiệu ứng khi thay đổi vị trí nút điều chỉnh. Nếu Slider thay vì vẽ thanh trượt và nút điều chỉnh trong một khung canvas duy nhất thì không thể thực hiện quá trình chuyển đổi, bởi vì quá trình này chỉ có thể áp dụng cho các phần tử HTML.

Phương thức initializeConstants() tạo các biến cho các hằng số của Slider, bao gồm các kiểu mặc định cho đường viền và nền mà phương thức initializeStrokeAndFillStyles() sử dụng khi không xác định được giá trị.

Phương thức thú vị nhất trong Liệt kê 5initializeKnob(), thiết lập các biến trước khi gọi phương thức createKnobCanvas() để tạo một canvas riêng biệt cho nút điều chỉnh của Slider. createKnobCanvas() tạo một phần tử canvas và thiết lập thuộc tính kiểu (style) của nó vì vậy canvas được đặt phía trên và bên trái khung bao quanh nó.

Bây giờ bạn đã biết cách khởi tạo canvas cho thanh trượt và nút điều chỉnh, hãy xem xét cách dùng chúng để vẽ Slider như thế nào.


Vẽ Slider

Phương thức draw()erase() của Slider được hiển thị trong Liệt kê 6.

Liệt kê 6. Vẽ và xóa Slider
COREHTML5.Slider.prototype = {
   ...

   erase: function() {
      this.railContext.clearRect(
         this.left - this.knobRadius, 0 - this.knobRadius,
         this.railCanvas.width  + 4*this.knobRadius,
         this.railCanvas.height + 3*this.knobRadius);

      this.knobContext.clearRect(0, 0, this.knobCanvas.width,
                                       this.knobCanvas.height);
   },

   draw: function (percent) {
      this.drawRail();
      this.drawKnob(percent ? percent : this.knobPercent );
   },
};

Phương thức erase() xóa cả hai canvas của Slider — cho thanh trượt và nút điều chỉnh. Ngược lại, phương thức draw() dùng để vẽ thanh trượt và nút điều chỉnh. Bạn có thể truyền vào một con số percent của nút điều chỉnh— giá trị của Slider — đến phương thức draw(), hay bạn có thể gọi nó mà không cần truyền vào đối số nào, trong trường hợp này, nó sẽ tự động dùng giá trị có sẵn của Slider.

Vẽ thanh trượt

Trong Liệt kê 7, thành phần Slider vẽ thanh trượt trong hai bước.

Liệt kê 7. Vẽ thanh trượt
COREHTML5.Slider.prototype = {
   ...
   drawRail: function () {
      var radius = (this.bottom - this.top) / 2;

      this.railContext.save();
      
      this.railContext.shadowColor   = this.SHADOW_COLOR;
      this.railContext.shadowOffsetX = this.SHADOW_OFFSET_X;
      this.railContext.shadowOffsetY = this.SHADOW_OFFSET_Y;
      this.railContext.shadowBlur = this.SHADOW_BLUR;

      this.railContext.beginPath();
      this.railContext.moveTo(this.left + radius, this.top);
      this.railContext.arcTo(this.right, this.top, this.right, this.bottom, radius);
      this.railContext.arcTo(this.right, this.bottom, this.left, this.bottom, radius);
      this.railContext.arcTo(this.left, this.bottom, this.left, this.top, radius);
      this.railContext.arcTo(this.left, this.top, this.right, this.top, radius);
      this.railContext.closePath();

      this.railContext.fillStyle = this.fillStyle;
      this.railContext.fill();
      this.railContext.shadowColor = undefined;
      this.railContext.restore();

      this.overlayRailGradient();

      this.railContext.restore();
   },

   overlayRailGradient: function () {
      var gradient =
         this.railContext.createLinearGradient(this.left, this.top,
                                           this.left, this.bottom);

      gradient.addColorStop(0,    'rgba(255,255,255,0.4)');
      gradient.addColorStop(0.2,  'rgba(255,255,255,0.6)');
      gradient.addColorStop(0.25, 'rgba(255,255,255,0.7)');
      gradient.addColorStop(0.3,  'rgba(255,255,255,0.9)');
      gradient.addColorStop(0.40, 'rgba(255,255,255,0.7)');
      gradient.addColorStop(0.45, 'rgba(255,255,255,0.6)');
      gradient.addColorStop(0.60, 'rgba(255,255,255,0.4)');
      gradient.addColorStop(1,    'rgba(255,255,255,0.1)');

      this.railContext.fillStyle = gradient;
      this.railContext.fill();

      this.railContext.lineWidth = 0.4;
      this.railContext.strokeStyle = this.strokeStyle;
      this.railContext.stroke();
   },
   ...
};

Đầu tiên, phương thức drawRail() của Slider tô màu nền cho thanh trượt với một màu đồng nhất, như trong Hình 4.

Hình 4. Nền của Slider
Vẽ khung của thanh trượt

Tiếp theo, phương thức drawRail() phủ lên một màu gradient trắng, như trong Hình 5.

Hình 5. Lớp phủ Slider
Vẽ lớp phủ của thanh trượt

Kết quả, như trong Hình 6, hiển thị thanh trượt trông sâu và có vẻ như có một ánh sáng chiếu vào nó.

Hình 6. Hợp thành Slider
Vẽ khung và lớp phủ của thanh trượt

Phương thức overlayRailGradient() của Slider sử dụng phương thức createLinearGradient() của HTML5 Canvas để tạo gradient. Sau đó, phương thức overlayRailGradient() thêm các điểm dừng màu dọc theo đường gradient. Mỗi điểm dừng là màu trắng trong với một độ mờ nhất định. Cuối cùng, phương thức overlayRailGradient() tô màu Slider với gradient và đường viền.

Vẽ nút điều chỉnh

Nút điều chỉnh mà Slider vẽ trong canvas riêng biệt, được hiển thị trong Hình 7.

Hình 7. Canvas của nút điều chỉnh
Hình ảnh nút thanh trượt, hiển thị màu của thanh trượt (rgba(255,255,0,0.5) và bản rút gọn tính năng vẽ nút: createKnobCanvas(). Tính năng đó tạo ra các nguyên tố canvas cho nút với dòng code: this.knobCanvas = document.createElement('canvas').

Hãy nhớ lại trong Liệt kê 5, Slider tạo canvas của nút điều chỉnh bằng cách gọi phương thức document.createElement(). Các phương thức fillKnob()strokeKnob() của Slider, được hiển thị trong Liệt kê 8, vẽ trong canvas đó.

Liệt kê 8. Vẽ nút điều chỉnh
COREHTML5.Slider.prototype = {
   ...

   drawKnob: function (percent) {
      if (percent < 0) percent = 0;
      if (percent > 1) percent = 1;

      this.knobPercent = percent;
      this.moveKnob(this.knobPercentToPosition(percent));
      this.fillKnob();
      this.strokeKnob();
   },
   
   fillKnob: function () {
      this.knobContext.shadowColor   = this.KNOB_SHADOW_COLOR;
      this.knobContext.shadowOffsetX = this.KNOB_SHADOW_OFFSET_X;
      this.knobContext.shadowOffsetY = this.KNOB_SHADOW_OFFSET_Y;
      this.knobContext.shadowBlur    = this.KNOB_SHADOW_BLUR;

      this.knobContext.beginPath();

      this.knobContext.arc(this.knobCanvas.width/2, this.knobCanvas.height/2,
                           this.knobCanvas.width/2-2, 0, Math.PI*2, false);

      this.knobContext.clip();

      this.knobContext.fillStyle = this.KNOB_FILL_STYLE;
      this.knobContext.fill();
   },

   strokeKnob: function () {
      this.knobContext.lineWidth = 1;
      this.knobContext.strokeStyle = this.KNOB_STROKE_STYLE;
      this.knobContext.stroke();
   },
   ...
};

Phương thức drawKnob() nắm giữ một số percent, đại diện cho vị trí của slider. Phương thức này thiết lập giá trị của Slider và di chuyển nút điều chỉnh phù hợp, sau đó tô màu và viền cho nút điều chỉnh.

Phương thức fillKnob() tô màu vàng mờ cho nút điều chỉnh, màu này cho phép nhìn xuyên qua thanh trượt bên dưới giống như nút điều chỉnh được chiếu sáng. Phương thức strokeKnob() vẽ viền cho nút điều chỉnh với màu đồng nhất.


Kéo nút điều chỉnh

Đoạn mã của Slider trong Liệt kê 9 cho phép kéo nút điều chỉnh.

Liệt kê 9. Kéo nút điều chỉnh
COREHTML5.Slider.prototype = {
   ...
   
   addMouseListeners: function () {
      var slider = this; // Let event handlers access this object

      this.knobCanvas.addEventListener('mousedown', function(e) {
         slider.draggingKnob = true;
         e.preventDefault();
      };
      
      this.knobCanvas.addEventListener('mousemove', function(e) {
         var mouse = null,
             percent = null;

         e.preventDefault();

         if (slider.draggingKnob) {
            mouse = slider.windowToCanvas(e.clientX, e.clientY);
            percent = slider.knobPositionToPercent(mouse.x);

            if (percent >= 0 && percent <= 1.0) {
               slider.erase();
               slider.draw(percent);
            }
         }
      }, false);

      this.knobCanvas.addEventListener('mouseup', function(e) {
         e.preventDefault();
         slider.draggingKnob = false;
      }; 
   }, 

   windowToCanvas: function(x, y) {
      var bbox = this.railCanvas.getBoundingClientRect();

      return {
         x: x - bbox.left * (this.railCanvas.width  / bbox.width),
         y: y - bbox.top  * (this.railCanvas.height / bbox.height)
      };
   },

   knobPositionToPercent: function(position) {
      var railWidth = this.right - this.left - 2*this.knobRadius;
          percent = (position - this.left - this.knobRadius) / railWidth;

      percent = percent > 1.0 ? 1.0 : percent;
      percent = percent < 0 ? 0 : percent;

      return percent;
   },
   ...
};

Hãy nhớ trong Liệt kê 4 rằng hàm khởi tạo của Slider gọi phương thức addMouseListeners() được hiển thị trong Liệt kê 9. Phương thức này thêm các hàm xử lý sự kiện chuột: mouse-down, mouse-move, và mouse-up vào canvas của nút điều chỉnh để xử lý việc kéo canvas nút điều chỉnh. Hai phương thức —windowToCanvas()knobPositionToPercent()— giúp việc này trở nên dễ hiểu hơn.


Bài tới

Trong bài này, bạn đã biết cách thực hiện một thành phần ad-hoc HTML5. Bài tiếp theo của loạt bài này sẽ tiếp tục khám phá thành phần Slider, hướng dẫn bạn cách hỗ trợ các bộ lắng nghe, sử dụng CSS để tạo hiệu ứng cho nút điều chỉnh của Slider, và thêm thành phần Slider vào cây DOM. Hẹn gặp bạn ở bài sau.


Tải về

Mô tảTênKích thước
Sample codewa-html5-components-1.zip8KB

Tài nguyên

Học tập

Lấy sản phẩm và công nghệ

Thảo luận

Bình luận

developerWorks: Đăng nhập

Các trường được đánh dấu hoa thị là bắt buộc (*).


Bạn cần một ID của IBM?
Bạn quên định danh?


Bạn quên mật khẩu?
Đổi mật khẩu

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Ở lần bạn đăng nhập đầu tiên vào trang developerWorks, một hồ sơ cá nhân của bạn được tạo ra. Thông tin trong bản hồ sơ này (tên bạn, nước/vùng lãnh thổ, và tên cơ quan) sẽ được trưng ra cho mọi người và sẽ đi cùng các nội dung mà bạn đăng, trừ khi bạn chọn việc ẩn tên cơ quan của bạn. Bạn có thể cập nhật tài khoản trên trang IBM bất cứ khi nào.

Thông tin gửi đi được đảm bảo an toàn.

Chọn tên hiển thị của bạn



Lần đầu tiên bạn đăng nhập vào trang developerWorks, một bản trích ngang được tạo ra cho bạn, bạn cần phải chọn một tên để hiển thị. Tên hiển thị của bạn sẽ đi kèm theo các nội dung mà bạn đăng tải trên developerWorks.

Tên hiển thị cần có từ 3 đến 30 ký tự. Tên xuất hiện của bạn phải là duy nhất trên trang Cộng đồng developerWorks và vì lí do an ninh nó không phải là địa chỉ email của bạn.

Các trường được đánh dấu hoa thị là bắt buộc (*).

(Tên hiển thị cần có từ 3 đến 30 ký tự)

Bằng việc nhấn Gửi, bạn đã đồng ý với các điều khoản sử dụng developerWorks Điều khoản sử dụng.

 


Thông tin gửi đi được đảm bảo an toàn.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=70
Zone=Nguồn mở
ArticleID=943620
ArticleTitle=Các thành phần của HTML5: Thành phần Ad-hoc, Phần 1
publish-date=09052013