Implementing a Slider control with the Atlas framework
Though the Atlas framework is in its CTP stage, there are already many controls available for use. For example, the Agility team is doing a great job with the Atlas Control Toolkit, a set of Atlas controls that can be used through extenders.
On the other hand, some classic client-side controls like a menu, a calendar or a slider are missing at the moment (but if you have coded one using the Atlas framework, please let me know). For this reason, I've decided to implement the last of these three controls: the slider.
Download the code
Usage
The slider control follows the "classic" Atlas approach of upgrading a portion of static html into an Atlas control. The static html should have the following structure:
<div id="slider" class="sliderRail">
<div id="handle" class="sliderHandle"><img src="Images/slider.handle.h.gif" alt="" /></div>
</div>
In the above code, we declared two layers: the first one is the "rail" or "line" container, and we should set its appearance through CSS and the background-image property (check the example that I've included in the archive). The other layer is declared as a child layer and represents the "handle" of the slider. In this case, while it would be better to set its appearance through the background-image property, I've used an img element to prevent an annoying IE issue that makes the image flicker if used through CSS (more info here). Once the static html has been declared, we can upgrade it into a Slider control with a declaration like the following, to be put in a xml-script section:
<slider id="horizSlider"
handle="slider2"
minimum="0"
maximum="100"
orientation="Horizontal"
value="54"
decimals="0"
enableSlideAnimation="true"
slideAnimationDuration="0.2"
/>
The slider control exposes the following properties (attributes in the declarative form):
- id, this has to be set to the id of the layer that represents the slider's rail.
- handle, has to be set to the id of the layer that represents the slider's handle.
- minimum, the minimum value that can be assigned to the slider.
- maximum, the maximum value that can be assigned to the slider.
- orientation, can be Horizontal or Vertical.
- value, used to get or set the slider's value.
- decimals, specifies the number of decimal digits used to represent the slider's value when getting it.
- steps, is used to obtain a slider with a "steps" movement instead of a continuous handle movement. The number of steps are specified setting this property.
- enableHandleAnimation, if set to true causes the handle to be animated when setting the value by clicking with the mouse on the slider's rail.
- handleAnimationDuration, specifies the duration of the handle animation, in seconds.
Finally, the control raises a valueChanged event every time the slider's value changes.
The problem: implementing a horizontal or vertical drag
One of the first thing that I've tried to implement when exploring the Atlas' drag and drop features was an horizontal or vertical drag. I thought that this would be an easy job, but then I found that the framework is totally responsible for setting the position of the control being dragged during a drag operation. So, no easy way to force an unidirectional dragging (or maybe you could have found an easy way to do that... in this case please email me). To work around this limitation, I had the idea to create an "invisible" drag handle: this drag handle is the object that the user is dragging around, but what the user sees moving is the "real" handle, i.e. the element specified through the handle property. Actually, the invisible handle is used to move the control that is supposed to be the real handle (if you browse through the code, you'll find a _initializeDragHandle method; try to change the style of the drag handle and you'll see what's happening). This has made possibile to implement an horizontal and vertical drag, and I've applied this concept to implement my slider control.
The code: a couple of interesting things
When building an Atlas control, the recommended approach is to "upgrade" some static html dropped on the page. To do this, is often necessary to supply elements' ids by setting control's attributes. The Atlas framework allows to directly reference a DOM element through its id, rather than passing its id and then getting the reference in the code. To do this, we have to simply declare a property and then specify in the getDescriptor method that that property will hold a reference to a DOM element. This feature has been used to specify the slider's handle:
td.addProperty('handle', Object, false, Sys.Attributes.Element, true);
Using the above code, the private member _handle will contain a reference to the corresponding DOM element.
The Sys.UI.LengthAnimation class, that is part of the visual effects framework defined in the AtlasUIGlitz.js file, allows to animate a property that is specified using a unit (for example, pixels). It allows to specify both the property to be animated and the unit to use (default is "px", i.e. pixels), and it's been used to implement the slide animation.
The Sys.UI.LayoutBehavior class, located in the AtlasUIGlitz.js file, allows to reference the layout properties of the associated control (left, top, height, width) through the corresponding properties, and it's been used in conjunction with the LengthAnimation class to implement the slide animation.
Conclusions
This was my first attempt to build a rather complex control using the Atlas framework, since I've also used animations and drag'n'drop features. This control is to be considered a work in progress at the moment, so be sure to often check this blog and the DotNetSlackers Community (where you'll find the code for all the releases) because I hope your feedback will drive the future releases of this control and help to improve it.