Vertical Slider with observable values

Hi, I imagine this must be pretty easy to do, but I’m having a hard time figuring it out. I’m trying to create a vertical slider on the right side of the screen that controls the value displayed inside a circle on the left side of the screen. I’m posting the code I have so far. Any help would be appreciated.

<App>
	<ClientPanel Background="0.8,0.8,0.8,1">

		<Grid RowCount="1" ColumnCount="2" Columns="8*,2*">
			
			<Panel Background="#0c0">
				<Circle Color="#fff">
					<Stroke Width="2" Color="#0ad"/>
					<Text ux:Name="CurrentValue" Value="{sliderText}" Alignment="Center" FontSize="300" Color="#0ad"/>
				</Circle>
			</Panel>

			<Panel Background="#c00">
				<RangeControl Alignment="HorizontalCenter" Padding="4,18,4,18" Height="300" ux:Name="rangeControl">
					<Rotation DegreesX="180"/>

					<JavaScript>
						var Observable = require("FuseJS/Observable");
						var sliderValue = Observable(0);
						var sliderText = Observable(function() { console.log("value = " + sliderValue.value.toFixed(2)); return sliderValue.value.toFixed(2) })
						module.exports = {
							sliderValue: sliderValue,
							sliderText: sliderText
						};
					</JavaScript>

					<DataBinding Target="rangeControl.Value" Key="sliderValue"/>
				    <LinearRangeBehavior Orientation="Vertical" />
					    <Panel>
					        <Circle ux:Name="thumb" Anchor="50%,50%" Alignment="Top" Width="28" Height="28">
								<SolidColor ux:Name="thumbFill" Color="#0ad" />
							</Circle>
					    </Panel>
					    <Rectangle Layer="Background" Color="#aaaaaa" CornerRadius="45">
							<SolidColor ux:Name="trackFill" Color="#fff" />		
							<Stroke Width="2" Color="#0ad"/>
						</Rectangle>
	
					    <ProgressAnimation>
					        <Move Target="thumb" Y="1" RelativeTo="ParentSize" />
					    </ProgressAnimation>
				</RangeControl>
			</Panel>

		</Grid>

	</ClientPanel>
</App>

Thanks,

Vlad

Your JavaScript is in the wrong place. The exports are only available downwards in the UX tree, thus the Text never sees the sliderText value. (Note: we have a pending issue to report when bindings never resolve, like in your case, but since it’s async, it’s tricky to get right.)

Nonetheless, the code can be simplified. You can bind to the value with this syntax in RangeControl: Value="{sliderValue}" instead. THis replaces the DataBinding, which should be almost non-existent in most apps.

The better way to convert to a text output is the .map function of the observable:

var sliderText = sliderValue.map( function(value) {
    return value.toFixed(2) 
})

This will also all work if you stick your RangeControl into a separate file as a ux:Class and just instantiate here.

Thank you for the help. I decided to scale back the control in order to get a minimal working vertical slider with a display. I’ve incorporated your suggestions in the code below - move javascript up; use reactive map function; use Value attribute in RangeControl instead of DataBinding.

It almost works now, but I can’t figure out why the thumb goes below the bottom of the track… It seems as if the padding for the bottom of the RangeControl doesn’t do anything…

<App>
	<ClientPanel>
		<Grid Rows="8*,2*">
			<JavaScript>
				var Observable = require("FuseJS/Observable");
				var sliderValue = Observable(0);
				var sliderText = sliderValue.map(function() { return sliderValue.value.toFixed(2); });
				module.exports = {
					sliderValue: sliderValue,
					sliderText: sliderText
				};
			</JavaScript>
			<RangeControl Padding="4,18,4,18" ux:Name="slider" Alignment="HorizontalCenter" Value="{sliderValue}">
				<!-- <Rotation DegreesX="180"/> -->
	
				<LinearRangeBehavior Orientation="Vertical" />	

				<ProgressAnimation>
					<Move Target="thumb" Y="1" RelativeTo="ParentSize" />
				</ProgressAnimation>

				<Circle ux:Name="thumb" Anchor="50%,50%" Alignment="Top" Width="28" Height="28">
					<SolidColor ux:Name="thumbFill" Color="#0ad" />
				</Circle>

			    <Rectangle Layer="Background" Color="#aaaaaa" CornerRadius="45">
					<SolidColor ux:Name="trackFill" Color="#fff" />		
					<Stroke Width="2" Color="#0ad"/>
				</Rectangle>

			</RangeControl>

			<Panel Background="#088">
				<Text ux:Name="currentValue" Color="#fff" Value="{sliderText}" Alignment="Right" Opacity="0.7"/>
			</Panel>
		</Grid>

	</ClientPanel>
</App>

Place the Circle inside a Panel. Currently you are moving it relative to the ParentSize. The immediate parent is the RangeControl itself, where Padding plays no influence on its own size. If you put a wrapping Panel however that Panel will have a size adjusted for the padding.

It probably makes sense to introduce a RelativeTo="ParentPaddingSize" to avoid the need for this, but UX expressions are coming soon anyway, so it may not be necessary.

Ah, that makes sense. Worked perfectly! Thanks!

I started with the halftone-effect example and it has

Focus.IsFocusable="true" HitTestMode="LocalBounds"

as attributes of RangeControl. Is this necessary? It does not seem to make a difference whether it’s there or not for the preview so I assume it must now be a default. Either that or maybe it does make a difference when it’s actually loaded on a real Android or iOS device…