HT graphical Component Design (2)
In the previous article, we customized the display interface effects of CPU and memory. In this article, we will continue to use HT to complete a new task: implement a knife gate control that can expand and merge switching actions. For the Human-Computer Interaction interfaces in the fields of electric SCADA and industrial control, a bunch of industry standard controls need to be predefined so that users can make visual editors, you can drag and drop to quickly build a specific electric power network or industrial control environment, set the parameter information such as the device's background number, and save the topology and metadata information to the background, in the actual running environment, the edited network topology information will be opened and connected to the real-time database in the background. The next step is to receive the collection information sent from the real-time database for real-time dynamic interface refreshing, the process includes various remote control and other operations performed by the user on the device through the client, which are sent to the backend to achieve control over the hardware device. This process is the basic architecture process of a typical real-time monitoring system. Today, we only do a good job of small screws and provide a controllable switch control.
Before implementation, let's take a look at the final film and video we want to achieve.
I remember that my first job I graduated more than a decade ago was responsible for the man-machine interface Interaction module of SCADA. At that time, most of the power industry used VC/MFC or QT to present interfaces, in fact, this is still the case so far. The front-end time and old friends gathered to learn that they are still using the VC6 compilation system. Today's VS20 ** cannot run their huge old system, of course, they may not have configured the tool parameters, but from one side you can feel the heavy lifting of the old system migration. Most programmers are struggling with the business functions of the project, over the years, hundreds of people have accumulated functions on the shelf where they could not be optimized or reconstructed. I remember that a mousedown function had accumulated more than six thousand lines of code, the draw code of various primitive types is also unsightly. Although these old systems are not easy to maintain, they have been tested by so many programmers. Every day, we can use water and electricity normally, it is backed by the blood and sweat of many programmers who are able to see completely unsightly bad code from today's perspective. I have to admit that using it in China is the first place. Other problems can be solved by a bunch of people. It's a little too far away. There are a few gallery tools I used to achieve electricity:
It is not difficult to implement functions. At that time, it also realized the combination and decomposition of elements, which can be used for image library management and user customization. I believe there must be no less than hundreds of thousands of Drawing Software sets around the world, at the beginning, I was very excited. I learned different drawing APIs every day to create new results. I don't care about the code architecture. Every day, I am proud to learn more about the huge MFC library, however, when you master most of the drawing skills, I find that I maintain this size every day, so that I cannot perform large-scale refactoring with my personal strength, and I have to continuously maintain the accumulation of functional and active code every day, I felt like I was wasting my life, so I switched to another company and planned to do e-commerce. As a result, I was scheduled to work on the drawing tool in the power department. Fortunately, this time I could change the language Java, no historical burdens completely re-design the graphic architecture, so there are 1,001st plotting tools on the earth:
The design of this version is still greatly improved. The graphic drawing logic, interactive code, and interface layout are all well-organized. The Java and design patterns are very popular, A notebook written by Martin Fowler, Refactoring: Improving the Design of Existing Code, is like an era in which religious beliefs firmly execute a function of no more than dozens of rows, thousands of lines of mousedown code have been extinct, but I am still not satisfied. The data model and interface drawing do not have a good combination mechanism, although the power demand interface has a *** response in milliseconds, most companies constantly repaint the interface like the game refresh mechanism. Yes, the data model at that time had no event dispatch mechanism, it is a pile of data in the memory. You can't know when to change the data, so you can only repaint the interface constantly. The refresh cycle is too short for large network topologies to be updated, the update cycle is too long and does not meet the response requirements. As for the so-called *** millisecond-level response, I can only handle it. In order to connect this system to a group of siblings in a rural area of Shenyang After being closed for more than eight months, I'm curious if the old system is healthy...
Back to our task, the most important part of a knife brake is the detachable part, and the other part is the decorative effect. Therefore, I use the HT vector to describe the appearance of the whole knife brake, the opening and closing part must be described using a line segment with the type of shape, and the rotation parameter is passed through func: 'style @ switch. angle to bind to the switch of the Node element. angle style attributes
- ht.Default.setImage('switch', {
- width: 100,
- height: 50,
- comps: [
- {
- type: 'roundRect',
- rect: [0, 0, 100, 50],
- background: '#2C3E50',
- gradient: 'linear.north'
- },
- {
- type: 'circle',
- rect: [10, 10, 10, 10],
- background: '#34495E',
- gradient: 'radial.center'
- },
- {
- type: 'circle',
- rect: [80, 10, 10, 10],
- background: '#34495E',
- gradient: 'radial.center'
- },
- {
- type: 'shape',
- points: [10, 40, 40, 40],
- borderWidth: 8,
- borderColor: '#40ACFF',
- border3d: true
- },
- {
- type: 'shape',
- points: [60, 40, 90, 40],
- borderWidth: 8,
- borderColor: '#40ACFF',
- border3d: true
- },
- {
- type: 'shape',
- points: [5, 40, 35, 40, 65, 40],
- segments: [1, 1, 2],
- borderWidth: 8,
- borderColor: '#40ACFF',
- border3d: true,
- borderCap: 'round',
- rotation: {
- value: -Math.PI/4,
- func: 'style@switch.angle'
- }
- },
- {
- type: 'circle',
- rect: [30, 35, 10, 10],
- borderColor: 'red',
- borderWidth: 5,
- border3d: true
- },
- {
- type: 'circle',
- rect: [60, 35, 10, 10],
- borderColor: 'red',
- borderWidth: 5,
- border3d: true
- }
- ]
- });
The above is opened in the vector editor. You can clearly see the demonstration of the position and size of several elements we have defined. In this way, you only need to build a Node object during the application, set the image to the switch vector. In the future, you only need to call node. setStyle ('Switch. angle ', Math. PI/6) allows you to control the angle of the knife gate at any time and anywhere.
This encapsulation is not perfect. For applications, they only care about the opening and closing operations of the knife gate. They do not care about the rotation angle. The opening and closing operations are the understanding of the business angle, while the rotation angle is the parameter on the underlying implementation graphics, and the user still needs to have an animation effect during the switch process, so we further encapsulate and design the ht. the Switch class provides the setExpanded function to operate the 'Switch. angle Property and startup animation encapsulation:
- ht.Switch = function(){
- ht.Switch.superClass.constructor.call(this);
- this.s('switch.angle', 0);
- };
- ht.Default.def('ht.Switch', ht.Node, {
- _image : 'switch',
- _icon: 'switch',
- toggle: function (anim) {
- this.setExpanded(!this.isExpanded(), anim);
- },
- isExpanded: function () {
- return this.s('switch.angle') !== 0;
- },
- setExpanded: function (expanded, anim) {
- if(anim == null){
- anim = true;
- }
- var self = this,
- animation = self._animation,
- oldValue = self.isExpanded();
- if(animation){
- animation.stop(true);
- delete self._animation;
- }
- if (oldValue !== expanded) {
- var targetAngle = expanded ? -Math.PI/4 : 0;
- if(anim){
- oldValue = self.s('switch.angle');
- self._animation = ht.Default.startAnim({
- action: function(t){
- self.s('switch.angle', oldValue + (targetAngle-oldValue)*t);
- }
- });
- }else{
- self.s('switch.angle', targetAngle);
- }
- }
- }
- });
In our video operations, you will find that you can control the opening angle of the knife gate at any time through the pull bar on the property page, and you can also select the opening and closing of the knife gate through the boolean attribute of isExpanded/setExpanded, careful programmers will find that not only are the switches on the topology drawing moved, but the icon corresponding to the switches on the TreeView is also the same as that in the vector description, what's even more surprising is that the icon on the tree also shows the angle of the knife gate in real time, which cannot be achieved by the icon image of the traditional image as the tree, this is what we have always stressed: the overall HT for Web architecture has laid the foundation for vector implementation, not just for topology. All common components enjoy the feature of vector, in the future, we will have more application cases to let everyone know the power of this combination. Of course, the maintainability is no longer needed, the custom renderer on the traditional generic component tree can also implement a dynamic icon, but you can think about the workload, we didn't write a line of code to draw, the GraphView and TreeView operations are done by defining a json vector. And the business interface is a node. setExpanded (true/false) for upper-layer applications.
Here I just made a very ugly, you can let the artist use the vector drawing tool to visually draw more beautiful results, you can also use graphView interface operations. mi monitors interactive events, such as switching when listening to double-click the knife gate. You can even refer to the section "viewing the essence of an animation Easing function through WebGL 3D" to adopt a more foreign Easing animation effect.
The following are some suggestions for designing controls:
- Switch to the user's perspective, that is, provide the most concise API interface that conforms to the business logic from the perspective of upper-layer users, and do not expose graphic parameters as much as possible. The graphic parameters are obscure to the upper layer, exposing yourself is also very difficult to modify and maintain
- Do not consider how to operate from the beginning. How to perform animation, operation, and animation can be extended and encapsulated on the basis of the Basic API. To some extent, how to operate and how to animation even does not belong to the control encapsulation. At least one layer of encapsulation can be provided, so that the operation and animation logic can be freely switched, without affecting the data model and drawing logic of the underlying control
- Try to separate the drawing code from the business logic code. If the most basic drawing code is used, it is really difficult to separate it. This is also the original intention of HT to adopt vector description as much as possible, so that users are not allowed to control the underlying drawing code.