Drag control problems + workaround

Hi,

I think the drag control is a bit tricky…let’s figure out if is possible to improve it! :wink:
(hope is in the right category, if not move it please)

SPACE/TIME RATIO

  1. the ratio between the mouse position and the slider position seems to be fixed, something like 100px/1s, this is fine when you understand how does it works: if I’ve to move my slider for 500px, so I’ve to move it in a time window of 5 seconds, so it follows the mouse position.

…but, if you scale the element you loose completely the sync between mouse position and the element position :’( Of course you can manually adjust the speed but if the layout is flexible there’s no way to do it.

You can find here this example/test:
Slider.hype.zip (28.1 KB)

Is there some kind of technique to avoid this for flexible dimensions? Would be great if Hype would manage this automagically…like checking if the element which is calling the drag event is scaled or not, for example.

EXECUTE ACTIONS
2. If I try to create a switch element, using two keyframes (at the beginning / end) to control 2 different actions (change slide, change timeline, javascript…), it doesn’t always work: is not 100% reliable.

Basically it works only if the “Continue after drag” option is active and you don’t move the timeline till the end, so (if you’re lucky :slight_smile: ) Hype plays by itself the rest of the timeline till the end (or the beginning) and the call works.

To fix/workaround this I developed a little JS function:

// Settings
var sliderTimeline = "Slider";
var triggerOff     = 'SwitchOff';
var triggerOn      = 'SwitchOn';

// get Symbol instance	
var symbolInstance = null;
var parentSymbolElement = element.parentNode;
while (symbolInstance == null && parentSymbolElement != null) {
    symbolInstance = hypeDocument.getSymbolInstanceById(parentSymbolElement.id);
    parentSymbolElement = parentSymbolElement.parentNode;
}

// Switch logic
if( symbolInstance.currentTimeInTimelineNamed(sliderTimeline) == 0 && element.getAttribute("switch") == "on" ) {

	element.setAttribute("switch", "off");
	hypeDocument.triggerCustomBehaviorNamed(triggerOff);
	
} else if( symbolInstance.currentTimeInTimelineNamed(sliderTimeline) == symbolInstance.durationForTimelineNamed(sliderTimeline) && ( !element.hasAttribute("switch") || element.getAttribute("switch") == "off" ) ) {

	element.setAttribute("switch", "on");
	hypeDocument.triggerCustomBehaviorNamed(triggerOn);

}

You can find everything in this example/test:
Sliders Drag Test.hype.zip (33.4 KB)

2 Likes

Hi Cescomare!

Nice work on your examples, Thank You.

1 Like

Ciao Francesco, bravo, bel lavoro.

this is a known problem, already discussed several times.

I made this example time ago

this is a common hype-problem. i posted this problem in march:

in your example, if you turn on flexible layout and set the "Wrapper" to scale per size, including context,
the mousecorsor moves slowlier than the slider itself.
there´s no solution for this problem at this moment.

That’s exactly what I was talking about, but no solutions it seems… :frowning:

SO…I spent my free time of the last days crushing my head on my Mac to find a workaround, and today I finally came out with a working script to trick Hype! :wink:

Maybe there’re some edge cases and bugs, but maybe you can help me to improve it! :slight_smile:

WHAT YOU NEED

  • a slider inside a Symbols with it’s timeline (“Slider” by default)
  • an hidden slider longer than the other one (“HiddenSlider” by default)
  • group the Symbol, add scale/flexible properties and add a class (“flexwrapper” by default)
  • with the On Drag event the handler moves the HiddenSlider (but NOT the Slider)
  • call to the “flexSlider()” function in the same On Drag event of the handler
  • define a target timeline to be controlled by the slider (it MUST have the same duration of the Slider timeline)

Enjoy! :wink:

// SETTINGS
var flexClass = "flexwrapper";
var parentElement = findAncestor( element, flexClass);
var sliderTimeline = "Slider";
var hiddenSliderTimeline = "Hidden" + sliderTimeline;
var targetTimeline = "Test";

// GET SYMBOL INSTANCE
var symbolInstance = null;
var parentSymbolElement = element.parentNode;

while (symbolInstance == null && parentSymbolElement != null) {
    symbolInstance = hypeDocument.getSymbolInstanceById(parentSymbolElement.id);
    parentSymbolElement = parentSymbolElement.parentNode;
}

// GET SCALE (default is 1:1)
var scale =  getElementScale(parentElement);

// CALCULATE HIDDEN TIMELINE END
var hiddenSliderTimelineEnd = symbolInstance.durationForTimelineNamed(sliderTimeline) * (  scale.x );

// UPDATE HIDDEN TIMELINE INDEX ON WINDOW RESIZE
if( !element.hasAttribute("flag") ) {
	window.onresize = function(event) {
	
		var scale =  getElementScale(parentElement);
		var newHiddenTimelinePos = symbolInstance.currentTimeInTimelineNamed( sliderTimeline ) * (  scale.x );
		
		symbolInstance.goToTimeInTimelineNamed( newHiddenTimelinePos, hiddenSliderTimeline );
		
		// UPDATE SCALE - You can remove this! ;)
		var el = document.getElementsByClassName("scale");
		
		for (var i = 0; i < el.length; i++) {
		    el[i].innerHTML = scale.x.toFixed(2);
		}
	};
	
	element.setAttribute("flag", "flag" );
}


// LIMIT HIDDEN TIMELINE IN RELATION OF THE REAL TIMELINE END
if( symbolInstance.currentTimeInTimelineNamed( hiddenSliderTimeline ) > hiddenSliderTimelineEnd ) {
	symbolInstance.goToTimeInTimelineNamed( hiddenSliderTimelineEnd, hiddenSliderTimeline );
}


// TIMELINE SCALE HACK
var scaledTime = symbolInstance.currentTimeInTimelineNamed( hiddenSliderTimeline ) * ( 1 / scale.x );

symbolInstance.goToTimeInTimelineNamed( scaledTime, sliderTimeline);


// UPDATE TARGET TIMELINE
hypeDocument.goToTimeInTimelineNamed( scaledTime, targetTimeline )


// FUNCTIONS

function getElementScale(elem) {

	var scale = {'x': 1, 'y': 1};
	
	if( elem ) {
		var transform = /matrix\([^\)]+\)/.exec(window.getComputedStyle(elem)['-webkit-transform']);
		
		if( transform ) {
			transform = transform[0].replace('matrix(', '').replace(')', '').split(', ');
			scale.x = parseFloat(transform[0]);
			scale.y = parseFloat(transform[3]);
		}
	}
	
	return scale;
}

function findAncestor (el, cls) {

	while ((el = el.parentElement) && !el.classList.contains(cls));

	return el;
}

Flex Slider.hype.zip (18.4 KB)

PS
I know is pretty complicated and requires an hidden Timeline and…blablabla…but I tried hard to overwrite Hype while its moving the handler and I couldn’t make it in that way… :’( I hope somebody can write something cleaner and easier following my approach! :smiley:

PPS
I know there’s a bug in the scale load at the first call: I was too lazy to fix it since is just for debugging :stuck_out_tongue:

1 Like

cool, seemed to work. my solution was to create a persistant symbol.
then create for each screen a layout and scale the persistant symbol to this size.
works, too. :smiley_cat:

2 Likes

Just wanted to reiterate this since it isn't well known: this is the correct formula. At the 100% speed setting it is 100px of finger movement is 1 second on the timeline.

Yes, I do consider this a bug.

Very cool!!!

One small thing that stands out is you're looking at the matrix from the transform; is there a reasons Hype's getter API can't be used since it exports the scaleX/scaleY properties for reasons like this?

I'd also say a more simple solution may instead be to simply drive it all by javascript; if you know the element you can use the approach to find the scale factor, and if you set a timeline to target, then you could just set the time directly on that. But Hype should help handle this :slight_smile:.

Thank you for the reply! :slight_smile:

There's no reason why I used the transform matrix instead of the API, but in fact using hypeDocument.getElementProperty(parentElement, 'scaleX') returns always 1...so I unconsciously did a good thing! :stuck_out_tongue:

So I think we have also discovered another problem:

I found a better way to do this: without a secondary Timeline! :smiley:

I hope you can understand what I did to make it smoother: I used a trick-in-the-trick :wink:

Now you can also decide the target Timeline just changing the Symbol class “target-NameOfTargetTimeline”! :wink:

Flex Slider 2.0.hype.zip (81.2 KB)

3 Likes

After my recent problems with PhoneGap I decided to change approach using the new HTML5 range input :slight_smile: Enjoy sliders with CSS3 transformations! :wink:

Range Input Timeline 1.0.hype.zip (18.9 KB)

2 Likes