Extends the Renderer and Editor of the HTML5 table component of HT for Web. html5renderer

Source: Internet
Author: User

Extends the Renderer and Editor of the HTML5 table component of HT for Web. html5renderer

Several commonly used editors are provided in HT for Web:


  • Slider: Pull bar
  • Color picker: color selector
  • Enum: Enumeration type
  • Boolean: true and false Editor
  • String: common text editor


In addition to these commonly used editors, you can also customize the editor by inheriting the ht. widget. BaseItemEditor class.

While the Renderer provides common Renderer in HT for Web:


  • Enum: Enumeration type
  • Color: color type
  • Boolean: true and false Renderer
  • Text: text Renderer


You can also customize the Renderer like the editor, but the method is not the same. The Renderer uses the drawCell () method in the definition column to customize the cell display effect.

Today, we will implement the Renderer and Editor of a custom HTML5 table component. To demonstrate the editing effect more intuitively, we just use the powerful HTML5 topology component of HT for Web.

First, let's look at the effect:



The second column in the left table defines an editor that uses a disc to indicate the Rotation Angle of the current text. You can drag it to implement angle conversion. The third column of the table, the drawCell () method is used to draw the cell content. The center line shows that the rotation angle is zero. To the left side, it indicates that the text is rotated counterclockwise and the right side indicates that the text is rotated clockwise and the specified angle.

HT for Web topology graph network node text, simple modification label. the rotation attribute enables text rotation. To make it more intuitive, I add a label. background makes the text of the network topology graph node have a background effect.

Next, let's take a look at the specific implementation. First, let's take a look at the implementation of the Renderer:

{    name : 'label.rotation',    accessType : 'style',    drawCell : function(g, data, selected, column, x, y, w, h, tableView) {        var degree = Math.round(data.s('label.rotation') / Math.PI * 180),                width = Math.abs(w /  * degree),                begin = w / 2,                rectColor = '#29BB9C',                fontColor = '#000',                background = '#F8F0E5';        if (selected) {            rectColor = '#F7F283';            background = '#29BB9C';        }        g.beginPath();        g.fillStyle = background;        g.fillRect(x, y, w, h);        g.beginPath();        if (degree < 0) begin -= width;        g.fillStyle = rectColor;        g.fillRect(x + begin, y, width, h);        g.beginPath();        g.font = '12px arial, sans-serif';        g.fillStyle = fontColor;        g.textAlign = 'center';        g.textBaseline = 'middle';        g.fillText(degree, x + w / 2, y + h / 2);    }}

The code above defines the code for the third column of the table. In addition to defining the column attributes, you can see that the drawCell () method is added and the parameters passed through the drawCell () method are also added, to draw the desired effect.

Rendering is so simple that the editor is not so easy. Before designing a custom editor, you must first understand the editor's base class ht. widget. BaseItemEditor. The Code is as follows:

ht.widget.BaseItemEditor = function (data, column, master, editInfo) {        this._data = data;    this._column = column;    this._master = master;    this._editInfo = editInfo;};ht.Default.def(‘ht.widget.BaseItemEditor’, Object, {    ms_ac:["data", "column", "master", "editInfo"],    editBeginning: function() {},    getView: function() {},    getValue: function() {},    setValue: function() {}});


In addition to the initialization class variables in the constructor, it defines several interfaces, allowing you to reload the relevant business operation logic. Then let's talk about the specific purpose of these interfaces:


  • EditBeginning: called before the cell editing starts.
  • GetView: Get the editor view. The value type is DOM element.
  • GetValue: Get the editor Value
  • SetValue: Set the editor value and initialize the editor page.


When creating a custom editor, you must implement these interfaces and perform different operations on different interfaces.

Now let's take a look at how custom editing of the rotation angle is designed:

1. According to the design convention of HT for Web components, we need to create a Div as a view. The view contains a canvas element, and the component content is drawn on the canvas;

2. the editor needs to interact with users. Therefore, you need to add event listening on the view to listen to possible operations of users. In this Demo, we want users to control the angle by dragging the angle control disk. Therefore, we added three event monitors: mousedown, mousemove, and mouseup on The view;

3. by dragging a component, you can change the angle. This change is continuous, and the mouse may leave the component area while dragging the component. to exit the component area, you can change the value correctly, at this time, you need to call the startDragging () method of HT for Web;

The operations described above are all processed in the constructor. Next, let's take a look at what the constructor looks like:

// Class ht. widget. rotationEditor constructor ht. widget. rotationEditor = function (data, column, master, editInfo) {// call the initialization parameter of the parent class constructor this. getSuperClass (). call (this, data, column, master, editInfo); var self = this, view = self. _ view = createDiv (1), canvas = self. _ canvas = createCanvas (self. _ view); view. style. boxShadow = '2px 2px 10px #000 '; // Add a mousemove listener to the view. addEventListener ('mousemove ', function (e) {if (self. _ state) {ht. default. startDragging (self, e) ;}}); // Add a mousedown listener to the view. addEventListener ('mousedown ', function (e) {self. _ state = 1; self. handleWindowMouseMove (e) ;}); // Add a mouseup listener to the view and clear the view. addEventListener ('mouseup', function (e) {self. clear ();});};

4. the next step is to define ht through the def () method. widget. the RotationEditor class inherits from ht. widget. baseItemEditor and implement the parent class method. The Code is as follows. In the code, I didn't post THE IMPLEMENTATION OF THE setValue () method. Because this is complicated, we will explain it separately;
Ht. default. def ('ht. widget. rotationEditor ', ht. widget. baseItemEditor, {editBeginning: function () {var self = this, editInfo = self. getEditInfo (), rect = editInfo. rect; // make a layout for the component before editing to prevent the component width and height from being computed incorrectly. layout (self, rect. x, rect. y, rect. width, rect. width) ;}, getView: function () {return this. _ view;}, getValue: function () {return this. _ value ;}, setValue: function (val) {// set the editor value and initialize the editor page }});


5. in the setValue () method, we need to plot the effects shown above the beginning of the article, which is roughly divided into the following four steps, of course, you need to wire the canvas context object before drawing:

5.1. Draw an internal and external disc and draw two concentric circles with 10 PX interval using the arc () method;

5.2. Draw a value area, draw a sector area by combining the arc () method and lineTo () method, and fill the color with the fill method;

5.3. Draw pointers and draw two pointers using the lineTo () method;

5.4. when drawing text, the text cannot be drawn directly at the center of the center, because the center of the center is the intersection of the pointer. If the text is drawn directly, it will overlap with the pointer, use the clearRect () method to clear the text area. Fill the background with the fillRect () method. Otherwise, the text area block will be transparent. Next, call the fillText () method to draw the text.

These are all the logics of component painting, but you must note that after the component is drawn, you must call the restore () method, because a save () operation is performed in the initContext () method () next, let's take a look at the specific implementation (the code is somewhat long );

SetValue: function (val) {var self = this; if (self. _ value = val) return; // sets the component value self. _ value = val; var editInfo = self. getEditInfo (), rect = editInfo. rect, canvas = self. _ canvas, radius = self. _ radius = rect. width/2, det = 10, border = 2, x = radius, y = radius; // convert degrees from radians to val = Math. round (val/Math. PI * 180); // sets the canvas size. setCanvas (canvas, rect. width, rect. width); // obtain the paint brush var g = initCo Ntext (canvas); translateAndScale (g, 0, 0, 1); // draw the background g. fillStyle = '# fff'; g. fillRect (0, 0, radius * 2, radius * 2); // set the line color and width g. strokeStyle = '#969698'; g. lineWidth = border; // draw the outer ring g. beginPath (); g. arc (x, y, radius-border, 0, Math. PI * 2, true); g. stroke (); // draw the inner ring g. beginPath (); g. arc (x, y, radius-det-border, 0, Math. PI * 2, true); g. stroke (); // draw the value area var start =-Math. PI/2, end = Math. PI * val/180-Math. PI/2; g. beginPath (); g. fillStyle = 'rgba (255, 0, 0, 0.7) '; g. arc (x, y, radius-border, end, start ,! (Val <0); g. lineTo (x, border + det); g. arc (x, y, radius-det-border, start, end, val <0); g. closePath (); // fill value area g. fill (); // draw the line g from the end of the value area to the center of the circle. lineTo (x, y); g. lineTo (x, det + border); g. stroke (); // draw the text var font = '12px arial, sans-serif'; // calculate the text size var textSize = ht. default. getTextSize (font, '-180'); // The text area var textRect = {x: x-textSize. width/2, y: y-textSize. height/2, width: textSize. width, height: textSize. height}; g. beginPath (); // clear the text area g. clearRect (textRect. x, textRect. y, textRect. width, textRect. height); g. fillStyle = '# fff'; // Add the background g. fillRect (textRect. x, textRect. y, textRect. width, textRect. height); // set the text style g. textAlign = 'center'; g. textBaseline = 'middle'; g. font = font; g. fillStyle = 'black'; // draw Text g. fillText (val, x, y); // restore () and save () are paired. The save () operation g has been performed in the initContext () method. restore ();}

6. At this time, the design of the editor is generally completed. How can I use the editor on a table? It's easy. When defining columns in a table, add the following two lines of code to start using the editor;

Editable: true, // start editing itemEditor: 'ht. widget. rotationedit' // pointing editor class

Here, the editor can be drawn normally, but during the operation, you will find that the editor does not change the angle based on the drag position. Why? Please refer to the following description:

7. In the constructor, the view mousemove event calls the startDragging () method. In fact, this method is dependent. It requires the component to overload handleWindowMouseMove () and handleWindowMouseUp () methods. The reason is very simple. As mentioned at, users may drag components away from the component area when dragging components, at this time, the user can only continue to operate through the mousemove and mouseup event listening on the window;

// Listen to the window's mousemove event. In the view's mousemove event, the startDragging () method is called, // while startDragging () the essence of the method is to trigger the window mousemove event // change the calculated value of this method, and use the setValue () method to change the value of handleWindowMouseMove: function (e) {var rect = this. _ view. getBoundingClientRect (), x = e. x-rect. left, y = e. y-rect. top, radius = this. _ radius, // calculate the radian using the inverse trigonometric function, and then convert the radian to the angle value = Math. round (Math. atan2 (y-radius, x-radius)/Math. PI * 180); if (value> 90) {value =-(180-value + 90);} else {value = value + 90;} this. setValue (value/180 * Math. PI) ;}, handleWindowMouseUp: function (e) {this. clear () ;}, clear: function () {// clear the status component Status delete this. _ state ;}

Add the preceding three methods and run the code to check that the editor can be edited normally. However, you can only view the text rotation angle changes on the topology graph after editing. If you can update the text Rotation Angle on the topology graph in real time, it will be more intuitive, so what should we do now?

8. the custom editor can specify the attributes of the editor as other implemented editors. The custom editor can only specify one class name, therefore, it is useless to set parameters in the editor. Users cannot set parameters in the editor. A clever method is to add an attribute named _ instant on the column, drawing on the design ideas of other editors, you can use this attribute value in the code to determine whether to update the corresponding attribute value immediately. Therefore, you only need to add the following code to the setValue () method to update the attribute value in real time;

// Determine whether the _ instant attribute if (column. _ instant) {var table = self. getMaster (); table. setValue (self. getData (), column, val );}

9. now, the editor has been designed. Now let's take a look at the specific usage. The following code is a specific column definition in Table. In the column definition, specify the itemEditor attribute value, set the _ instant attribute to true to update the editor in real time.


{    accessType : 'style',    name : 'label.rotation',    editable : true,    itemEditor : 'ht.widget.RotationEditor',    _instant : true,    formatValue : function(value) {        return Math.round(value / Math.PI * 180);    }}


In the code, you will find that a formatValue () method is defined to be consistent with the value type edited in the editor and converts radians to degrees.

In the third column of the table, the cell style is customized through the Renderer, and I have also defined another editor for it. The angle is changed by dragging the cells left and right, the implementation of this editor is slightly different from the editor mentioned above. The difference is that the editor in the third column adds listeners through the ms_listener module defined in HT for Web, it seems clearer to let the constructor and interaction split away.

This section describes the ms_listener module. If the ms_listener module is added to the class, the following two methods will be added to the class:


  • AddListeners: add the handle_XXX () method defined in the class (XXX represents the name of a DOM event, such as mousemove) as the corresponding event listening function to the view of the component;
  • RemoveListeners: removes the event corresponding to the handle_XXX () method defined in the class from the view.


So how to add the ms_listener module to the class? You only need to add the ms_listener: true line of code in the method definition of the class in the def () method, add the handle function corresponding to the DOM event to the method definition, and then call the addListeners () method of the class in the constructor.

I will not elaborate on the specific code. The idea is similar to the idea of the editor described above.

The code of the program is attached for your reference. If you have any questions, please leave a message.

TableRendererEditor.zip


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.