Original: Creating Custom Layouts in Ext JS and Sencha Touch
The layout system is the most powerful and unique part of the Sencha framework. The layout handles the size and position of each component in the application, so there is no need to manually manage those fragments. There are many similarities between Ext JS and Sencha Touch's layout class, which was recently analyzed in detail in the blog post of Ivan Jouikov.
Although this is the case, many Ext JS and Sencha Touch developers may never be able to understand the mechanics of the layout system. The Sencha framework already provides the most common application layouts, so there is little need for additional functionality in the application, so there is no General Assembly who wants to understand the internal workings of the layout system.
Imagine that your company needs to use 3D carousel in your application to display interface elements, but no standard sencha layouts can provide this capability, how do you solve this problem?
Select Base class
When developing any Ext JS or Sencha Touch custom components, the first step to consider is always to choose which base class to extend. In this case, it is the project that needs to use the layout to accommodate 3D space. Because you do not need any special features, just manage the project, you need to start with the minimum layout inheritance chain. In the current situation, Ext.layout.container.Container (Ext JS) and Ext.layout.Default (Sencha Touch) can be said to be the best choice.
In Ext JS, because of the need to support the legacy browser, but not some modern CSS features, such as Flexbox, so the layout system needs to manually manage a lot of size and positioning calculations. The consequence is that the 3D carousel layout needs to rewrite most of the Ext.layout.container.Container methods, such as calculate, Getcontainersize, and Getpositionoffset, To lay out the child elements of it.
Another issue to note is that the Ext JS layout in the "layout" when the execution of each "layout" to manage multiple "cycles", for example, the box layout is configured to Stretchmax need at least two cycles, layout first to detect the maximum size of each sub-component, and the sub-components within all layouts are expanded to the same size in the second cycle. The operation of the layout results in a large number of "layouts" or "periods" (adding or removing multiple entries), and in order to provide performance, you might want to pause the layout before the operation is complete before restoring the layout.
By contrast, Sencha Touch's Ext.layout.Default allows the browser to handle the positioning and size of most items in the layout via CSS (since Sencha touch only supports modern browsers, all of which implement CSS Flexbox). Therefore, Ext.layout.Default contains the main methods associated with adding, removing, and relocating sub-entries.
Now that you know what classes will be used to extend the new 3D carousel layout, let's step through the implementation.
CSS3 Conversion and other magic
In order to create a 3D Carousel, you need to use some advanced CSS 3D transformations, such as transformations, transitions, rotatex/rotatey, and Translatez. CSS 3D transformations can be very replicated, but in general, the following things are required for the new Sencha layout:
Apply perspective and transformations in the parent container (let it appear to be 3D)
Sub-components within layouts apply transformations (rotate them around 3D shapes from their boundaries)
Applying transformations to DOM elements inside the parent container (o physically rotate the 3D shape as the user interacts with it)
As you might expect, the actual DOM elements generated by the Ext JS and Sencha Touch will be slightly different, so although the methods taken in the two frameworks are the same, the resulting CSS will still have a difference. The additional CSS required for the new 3D carousel layout is as follows (Sencha Touch):
. x-layout-carousel {-webkit-perspective:1500px; -moz-perspective:1500px; -o-perspective:1500px; perspective:1500px; Position:relative!important;} . X-layout-carousel. x-inner {-webkit-transform-style:preserve-3d; -moz-transform-style:preserve-3d; -o-transform-style:preserve-3d; Transform-style:preserve-3d;} . x-layout-carousel.panels-backface-invisible. x-layout-carousel-item {-webkit-backface-visibility:hidden; -moz-backface-visibility:hidden; -o-backface-visibility:hidden; Backface-visibility:hidden;} . x-layout-carousel-item {display:inline-block; Position:absolute!important;} . X-layout-carousel-ready. x-layout-carousel-item {-webkit-transition:opacity 1s,-webkit-transform 1s; -moz-transition:opacity 1s,-moz-transform 1s; -o-transition:opacity 1s,-o-transform 1s; transition:opacity 1s, transform 1s;} . X-layout-carousel-ready. X-inner {-webkit-Transition:-webkit-transform 1s; -moz-transition:-moz-transform 1s; -o-transition:-o-transform 1s; Transition:transform 1s;}
In order for the Ext JS layout css to look basically the same, you need to do some fine-tuning the CSS selector.
To allow 3D carousel to respond to user interaction in Sencha Touch and Ext JS, you have to modify some of the additional CSS at run time. The first thing to do is to extend the base class of the layout and then explore how to add interactivity.
Extending the layout base class
First of all, to extend the Ext.layout.Default of Sencha touch, the main goal is to add some configuration items for the look and feel of the new 3D carousel, and some of the features inside the layout to properly position the subcomponents.
The initial expansion is as follows:
Ext.define (' Ext.ux.layout.Carousel ', { extend: ' Ext.layout.Default ', alias : ' Layout.carousel ', Config: { /** * @cfg {number} portalheight * Height of the carousel, in pixels */ portalheight:0,
/** * @cfg {number} portalwidth * Width of the carousel, in pixels * /portalwidth: 0, /** * @cfg {string} direction * ' horizontal ' or ' vertical ' * /direction: ' Horizontal '//or ' Vertical ' }, onitemadd:function () { this.callparent (arguments); This.modifyitems (); }, onitemremove:function () { this.callparent (arguments); This.modifyitems (); }, modifyitems:function () { //calculate child positions, etc }});
In addition to the Config object, 3 methods are defined in the code: Onitemadd, Onitemremove, and Modifyitems. The first Lang method simply overrides the Ext.layout.Default method to edit the position of the subassembly after the subassembly is added or removed, and Modifyitems is a new method to calculate the required CSS 3D transformations.
When layouts are assigned to their containers, the behavior inside the layout system is always active:
Setcontainer:function (Container) { var options = { delegate: ' > Component ' }; This.dockeditems = []; This.callsuper (arguments); Container.on (' Centeredchange ', ' onitemcenteredchange ', this, options, ' before ') . On (' Floatingchange ', ' Onitemfloatingchange ', this, options, ' before ') . On (' Dockedchange ', ' onbeforeitemdockedchange ', this, options, ' Before ') . On (' Afterdockedchange ', ' onafteritemdockedchange ', this, options);},
For our layout extensions, for further initialization, we need to add the following methods:
Ext.define (' Ext.ux.layout.Carousel ', {//... setcontainer:function (container) {var me = this; Me.callparent (arguments); me.rotation = 0; Me.theta = 0; Switch (Ext.browser.name) {case ' IE ': me.transformprop = ' mstransform '; Break Case ' Firefox ': me.transformprop = ' moztransform '; Break Case ' Safari ': Case ' Chrome ': me.transformprop = ' webkittransform '; Break Case ' Opera ': me.transformprop = ' otransform '; Break Default:me.transformProp = ' webkittransform '; Break } me.container.addCls (' X-layout-carousel '); Me.container.on (' painted ', Me.onpainthandler, ME, {single:true}); }, Onpainthandler:function () {var me = this; Add the ' Ready ' class to set the CSS transitionState Me.container.addCls (' X-layout-carousel-ready '); Set the drag handler on the underlying DOM Me.container.element.on ({drag: ' Ondrag ', DragStart: ' ondragstart ', dragend: ' Ondragend ', scope:me}); Me.modifyitems (); } });
After nebulous assigns a layout container, you must wait until the container is rendered before you can assign event handling to the underlying DOM. Next, in order to allow the layout to manage the subcomponents, also fill in the gap between the functions (fill in the functional gaps):
Ext.define (' Ext.ux.layout.Carousel ', {//... modifyitems:function () {var me = this, Ishorizo Ntal = (Me.getdirection (). toLowerCase () = = = ' horizontal '), CT = me.container, Panelcount = Ct.items. GetCount (), panelsize = ct.element.dom[ishorizontal? ' offsetwidth ': ' offsetheight '], i = 0, panel, angle; Me.theta = 360/panelcount; Me.rotatefn = IsHorizontal? ' Rotatey ': ' Rotatex '; Me.radius = Math.Round ((PANELSIZE/2)/Math.tan (Math.pi/panelcount)); For each child item in the layout ... for (i; i < Panelcount; i++) {panel = ct.items.getAt (i); Angle = Me.theta * I; Panel.addcls (' X-layout-carousel-item '); Rotate panel, then push it out in 3D space panel.element.dom.style[me.transformprop] = me.rotatefn + ' (' + Angle + ' deg) Translatez (' + Me.radius + ' px) '; }//Adjust rotation so PANels is always flat me.rotation = Math.Round (me.rotation/me.theta) * ME.THETA; Me.transform (); }, Transform:function () {var me = this, el = me.container.element, h = El.dom.offsetH Eight, style= El.dom.style; Push the carousel back in 3D space, and rotate it el.down ('. X-inner '). dom.style[Me.transformprop] = ' translate Z (-' + Me.radius + ' px) ' + me.rotatefn + ' (' + me.rotation + ' deg) '; Style.margin = parseint (H/2, ten) + ' px auto '; Style.height = me.getportalheight () + ' px '; Style.width = me.getportalwidth () + ' px '; }, Rotate:function (increment) {var me = this; Me.rotation + = Me.theta * Increment *-1; Me.transform (); }});
In the example, you also xu a large number of complex operations to determine the correct location for each sub-component, as well as the conversion values that require the CSS to be manually updated within the container.
Finally, you need to add event handling to capture the interaction between the user and the 3D carousel:
Ext.define (' Ext.ux.layout.Carousel ', { //... Ondragstart:function () { this.container.element.dom.style.webkitTransitionDuration = "0s"; }, Ondrag: Function (e) { var me = this, ishorizontal = (me.getdirection (). toLowerCase () = = = ' Horizontal '), Delta; if (ishorizontal) { delta =-(E.deltax-e.previousdeltax)/Me.getportalwidth (); } else { Delta = (e.deltay-e.previousdeltay)/Me.getportalheight (); } Me.rotate (Delta *). toFixed ()); }, ondragend:function () { This.container.element.dom.style.webkitTransitionDuration = "0.4s";
Event handling simply evaluates whether the user has dragged the mouse to carousel and then updates the CSS transitions.
This complete Sencha Touch code can be downloaded here. And the extension from Ext.layout.container.Container's Ext JS code is very similar to this, but there are some small differences in the API. An example of Ext JS code can be downloaded here.
Review Ext.ux.layout.Carousel
Let's take a little time to review what's going on.
Because the 3D carousel layout only needs to inherit the basic functionality of the layout system, the Ext.layout.Default class of Sencha Touch is selected for expansion. Next, an overriding method, such as Onitemadd, Onitemremove, and Setcontainer, is added to add the run configuration required for the layout. It is best to implement some functional methods and event handling so that the layout can manage the location of the subcomponents.
Although 3D Carousel is a whimsical example created using Sencha touch or Ext JS, its focus is on creating creative layouts in Sencha applications, which is actually simple. The key is to know how to initialize the layout and what happens during that time-the underlying framework code is not as complex as you might think. Sencha Touch and Ext JS layout system, although at the bottom there will be slightly different, but the implementation method is actually the same.
Please note: This is just a technical demonstration and there is no guarantee that the code will run on all browsers. In fact, the CSS3 conversion used already means that some browsers have been removed, so please do not apply this to production.
Other interesting examples of customized layouts include this Sencha fiddle by Sencha support Engineer Seth Lemmons Involv ing a circle menu, and this video of a custom navigation component by Andrea Cammarata, Sencha Professional Services Engin EEr.
Arthur Kay
Arthur Kay is the Developer relations Manager at Sencha, Inc. He studied Music and computer science at Loyola University Chicago and have been involved with the WEB since the late 1990s .