Halftone effect

Using the JavaScript Camera API, we create a small app that lets you take pictures with a halftone effect. The effect parameters can then be tweaked with some custom styled slider controls.

Taking a picture

We create a function in JavaScript called takePicture which we bind to from UX.

var picture = Observable('Icons/background.jpg');
var filterApplied = Observable(false);

function takePicture(){
    Camera.takePicture(1000, 1200).then(function(file){
        picture.value = file;
        filterApplied.value = false;
    }).catch(function(e) {
        console.log(e);
        filterApplied.value = false;
    });
};

It will open the default camera app on the device, and return the resulting file. We can then put that file in our picture Observable which we bind to from UX. In addition to working with the picture, we also change the value of a boolean Observable called filterApplied, so that we can decide to show the picture with or without the halftone filter in UX.

Halftone

<Image ux:Name="picture" File="{picture}" StretchMode="UniformToFill">
    <WhileTrue Value="{filterApplied}">
        <Halftone ux:Name="halftone" Intensity="0" Smoothness="0" Spacing="5" PaperTint="0" DotTint="0" />
    </WhileTrue>
    <AddingAnimation>
        <Change picture.Opacity="0" Duration="0.5" />
    </AddingAnimation>
</Image>

We data-bind an Image element to the picture Observable and add a Halftone effect to it with some default values. We give the effect a name, which we will reference from some sliders. Note how we only enable the filter when the filterApplied boolean Observable is true.

Creating a custom slider

<RangeControl ux:Class="MySlider" Focus.IsFocusable="true" MinHeight="30" Padding="5" Margin="18,4" HitTestMode="LocalBounds">
    <string ux:Property="Text" />
    <float4 ux:Property="Highlight" />

    <LinearRangeBehavior />
    <StackLayout />

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

    <Panel Alignment="Top" Margin="6,10,0,0">
        <DataBinding Target="this.Value" Key="sliderValue" />
        <Text ux:Name="currentValue" Value="{sliderText}" Alignment="Right" Opacity="0.7" />
        <Panel ux:Name="thumb" Anchor="50%,50%" Alignment="Left" Width="15" Height="15" HitTestMode="LocalBounds">
            <Rectangle Color="{ReadProperty Highlight}" />
        </Panel>
        <Panel Layer="Background">
            <Rectangle Height="6" Color="{ReadProperty Highlight}" Opacity="0.3" />
            <Rectangle Height="6" Color="#fff" />
        </Panel>
    </Panel>
    <Text Value="{ReadProperty Text}" Alignment="BottomLeft" Margin="6,0,0,0" />

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

</RangeControl>

To create a custom slider, we use the LinearRangeBehavior. This behavior handles everything related to the input of a RangeControl. We then use the ProgressAnimation trigger to animate the appearance of our Slider in response to the users input.

Tweaking the effect with our sliders

We can tweak the halftone effect directly from UX using our newly created sliders. We use ux:Property bindings to customize the sliders color and text properties by passing them in from MainView.ux.

<WhileTrue Value="{filterApplied}">
    <Grid RowCount="3" Margin="0,30,0,10">
        <FadeInPanel>
            <MySlider Text="Intensity" Highlight="#50D2C2">
                <ProgressAnimation>
                    <Change halftone.Intensity="2" />
                </ProgressAnimation>
            </MySlider>
            <Rectangle Height="1" Color="#eee" Alignment="Bottom" />
        </FadeInPanel>
        <FadeInPanel>
            <MySlider Text="Smoothness" Highlight="#FCAB53">
                <ProgressAnimation>
                    <Change halftone.Smoothness="15" />
                </ProgressAnimation>
            </MySlider>
            <Rectangle Height="1" Color="#eee" Alignment="Bottom" />
        </FadeInPanel>
        <FadeInPanel>
            <MySlider Text="Spacing" Highlight="#BA77FD">
                <ProgressAnimation>
                    <Change halftone.Spacing="15" />
                </ProgressAnimation>
            </MySlider>
        </FadeInPanel>
    </Grid>
</WhileTrue>

We use the ProgressAnimation trigger together with Change animators to react to the user sliding.

Each MySlider is surrounded by a FadeInPanel. This is just a normal Panel with an AddingAnimation which animated the panels Opacity.

<Panel ux:Class="FadeInPanel" ux:Name="fadeInPanel">
    <AddingAnimation>
        <Change fadeInPanel.Opacity="0" Duration="0.5" />
    </AddingAnimation>
</Panel>