iPhone Unlock Slider With Mootools? - iphone

I try to make a slider similar to the iPhone unlock Slider, that forwards to a linked site, when complete, and returns to its initial position when the slider wasn't dragged to the end.
This is not meant to be a iPhone webapp, i just want to put this to a general website as a effect.
So far I've tried those two tests, but i'm stuck on both.
The first is:
// First Example
var el = $('slideOne'),
// Create the new slider instance
var sliderOne = new Slider(el, el.getElement('.slider'), {
steps: 20, // There are 35 steps
range: [8], // Minimum value is 8
}).set(20);
Problem here is that i can't fire an event on (0) not on (20) aswell, i tried onComplete but this fires the function immediatly after the page is load!?
The second
$$('.textslider').setStyle('opacity', 0.8);
$('slider1').makeDraggable({
snap: 0,
container: 'slideOne',
droppables: '.slidedrop1',
onDrop: function(element, droppable, event){
if (!droppable);
else console.log(element, 'dropped on', droppable, location = 'index.php/kredite.html', event);
},
});
Problem here is , that the droppable don't work as fine as i hoped, sometimes i move the the slider on the invisible droppable, which indicates if the slider is dragged to the end, and nothing happens, sometimes it works fine, i think this may be due the different position of the cursor on the slider. and i can't get it done that it is only possible to slide horizontal , since it is that drag not the slider function, so i think this won be the proper way.
On both Tests, i didn't figured out who i could return the slider back to its initial position, with a slide Effect.
Are there some mootools cracks around who maybe could help me with this? Thanks already for the great ideas of y'all.

<html>
<head>
<script type="text/javascript"
src="http://demos.mootools.net/demos/mootools.js"></script>
<script type="text/javascript">
window.addEvent('domready', function(){
var el = $('slideOne');
var debug = $('debug');
var ACTIVATE_VALUE = 20;
var mySlider = new Slider(el, el.getElement('.knob'), {
range: [0], // Minimum value
steps: ACTIVATE_VALUE, // Number of steps
onChange: function(value){
if (value == ACTIVATE_VALUE) {
debug.setStyles({color:'green'});
// go to url after delay
(function(){
location.href='http://joecrawford.com/';
}).delay(500);
} else {
debug.setStyles({color:'red'});
// if not activated, reset after 2 second delay
(function(){
value = 0;
mySlider.set(value);
}).delay(3000);
}
debug.set('text', value);
}
});
mySlider.set(0);
});
</script>
<style type="text/css">
div.slider {
width: 200px;
height: 50px;
background: #eee;
}
div.slider div.knob {
background: #000;
width: 50px;
height: 50px;
}
div#debug {
font-family: sans-serif;
font-size: xx-large;
}
</style>
<title>Slider that resets if it does not reach the end</title>
</head>
<body>
<div id="slideOne" class="slider">
<div class="knob"></div>
</div>
<div id="debug">-</div>
</body>
</html>

Related

setTimeout vs requestAnimationFrame

I made an example of 'setTimeout vs requestAnimationFrame' to find out how different they are.
As you can see, the orange box arrives to the destination first. The green box jump some times and slower.
I understand why the green box jump some times. Because the task(calling move function) would not be inserted in macroTaskQueue before repaint some times(this is called jank or frame skip).
This is why I prefer requestAnimationFrame than setTimeout when animate element. Because the move() of requestAnimationFrame(move) is guaranteed to be called right before repaint.
Now, what I'm wondering is that why the green box is slower than orange box
Maybe does it mean that the move() is not called at each 1000/60 ms?
setTimeout is always late.
The way it works is
Register a timestamp when to execute our task.
At each Event loop's iteration, check if now is after that timestamp.
Execute the task.
By this very design, setTimeout() is forced to take at least the amount of time defined by delay. It can (and will often) be more, for instance if the event loop is busy doing something else (like handling user gestures, calling the Garbage Collector, etc.).
Now since you are requesting a new timeout only from when the previous callback got called, your setTimeout() loop suffers from time-drift. Every iteration it will accumulate this drift and will never be able to recover from it, getting away from the wall-clock time.
requestAnimationFrame (rAF) on the other hand doesn't suffer from such a drift. Indeed, the monitor's V-Sync signal is what tells when the event loop must enter the "update the rendering" steps. This signal is not bound to the CPU activity and will work as a stable clock. If at one frame rAF callbacks were late by a few ms, the next frame will just have less time in between, but the flag will be set at regular intervals with no drift.
You can verify this by scheduling all your timers ahead of time, your setTimeout box won't suffer from this drift anymore:
const startBtn = document.querySelector('#a');
const jankBtn = document.querySelector('#b');
const settimeoutBox = document.querySelector('.settimeout-box');
const requestAnimationFrameBox = document.querySelector('.request-animation-frame-box');
settimeoutBox._left = requestAnimationFrameBox._left = 0;
let i = 0;
startBtn.addEventListener('click', () => {
startBtn.classList.add('loading');
startBtn.classList.add('disabled');
scheduleAllTimeouts(settimeoutBox);
moveWithRequestAnimationFrame(requestAnimationFrameBox);
});
function reset() {
setTimeout(() => {
startBtn.classList.remove('loading');
startBtn.classList.remove('disabled');
i = 0;
settimeoutBox.style.left = '0px';
requestAnimationFrameBox.style.left = '0px';
settimeoutBox._left = requestAnimationFrameBox._left = 0;
}, 300);
}
function move(el) {
el._left += 2;
el.style.left = el._left + 'px';
if (el._left > 1000) {
return false;
}
return true;
}
function scheduleAllTimeouts(el) {
for (let i = 0; i < 500; i++) {
setTimeout(() => move(el), i * 1000 / 60);
}
}
function moveWithRequestAnimationFrame(el) {
if (move(el)) {
requestAnimationFrame(() => {
moveWithRequestAnimationFrame(el);
});
} else reset();
}
.grid {
margin: 30px !important;
padding: 30px;
}
.box {
width: 200px;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
color: white;
font-size: 18px;
}
.settimeout-box {
background-color: green;
}
.request-animation-frame-box {
background-color: orange;
}
<div class="ui grid container">
<div class="row">
<button class="ui button huge blue" id="a">Start!</button>
</div>
<div class="row">
<div class="box settimeout-box">
<span>setTimeout</span>
</div>
</div>
<div class="row">
<div class="box request-animation-frame-box">
<span>requestAnimationFrame</span>
</div>
</div>
</div>
Note that Firefox and Chrome actually do trigger the painting frame right after the first call to rAF in a non-animated document, so rAF may be one frame earlier than setTimeout in this demo.
requestAnimationFrame's frequency is relative to the monitor's refresh-rate.
Above example assumes that you run it on a 60Hz monitor. Monitors with higher or lower refresh rate will enter this "update the rendering" step at different frequencies.
Also beware, delay in setTimeout(fn, delay) is a long, this means the value you pass will be floored to integer.
An a last note, Chrome does self correct this time drift in its setInteval() implementation, Firefox and the specs still don't, but it's under (not so active) discussion.

Leaflet.js: Use ctrl + scroll to zoom the map & Move map with two fingers on mobile

I'm using http://leafletjs.com/ ... is it possible to only:
Use ctrl + scroll to zoom the map
Move map with two fingers on mobile/tablet
... so similar what google maps does? With the comments ...
So far thats my setup:
// Leaflet Maps
var contactmap = L.map('contact-map', {
center: [41.3947688, 2.0787279],
zoom: 15,
scrollWheelZoom: false
});
There is an amazing library that does exactly that. Leaflet.GestureHandling
It is an add on to leaflet that works right of the box, it's also modular and can be installed using npm.
Here's a working example using leaflet and GestureHandling.
You can try it also on mobile.
P.S. It has multiple languages baked in:)
// Attach it as a handler to the map
const map = L.map('map', {
gestureHandling: true
}).setView([51.505, -0.09], 13);
// Add tile layer
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
#map {
height: 400px;
width: 400px;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.4.0/dist/leaflet.css"
integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA=="
crossorigin=""/>
<link rel="stylesheet" href="//unpkg.com/leaflet-gesture-handling/dist/leaflet-gesture-handling.min.css"
type="text/css">
<script src="https://unpkg.com/leaflet#1.4.0/dist/leaflet.js"
integrity="sha512-QVftwZFqvtRNi0ZyCtsznlKSWOStnDORoefr1enyq5mVL4tmKB3S/EnC3rRJcxCPavG10IcrVGSmPh6Qw5lwrg=="
crossorigin=""></script>
<script src="//unpkg.com/leaflet-gesture-handling"></script>
<div id="map"></div>
zoom map using ctrl + zoom. I did in custom way .
html code is below
<div id="map"></div>
css
.map-scroll:before {
content: 'Use ctrl + scroll to zoom the map';
position: absolute;
top: 50%;
left: 50%;
z-index: 999;
font-size: 34px;
}
.map-scroll:after {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
content: '';
background: #00000061;
z-index: 999;
}
jQuery
//disable default scroll
map.scrollWheelZoom.disable();
$("#map").bind('mousewheel DOMMouseScroll', function (event) {
event.stopPropagation();
if (event.ctrlKey == true) {
event.preventDefault();
map.scrollWheelZoom.enable();
$('#map').removeClass('map-scroll');
setTimeout(function(){
map.scrollWheelZoom.disable();
}, 1000);
} else {
map.scrollWheelZoom.disable();
$('#map').addClass('map-scroll');
}
});
$(window).bind('mousewheel DOMMouseScroll', function (event) {
$('#map').removeClass('map-scroll');
})
In simple way when user scroll on map then detect ctrl button is pressed or not then just I add one class that will showing message on map. and prevent screen zoom-in and zoom-out outside of map.
I managed to solve your second problem.
I used css for displaying the message using a ::after pseudo selector.
#map {
&.swiping::after {
content: 'Use two fingers to move the map';
}
}
And javascript to capture the touch events.
mapEl.addEventListener("touchstart", onTwoFingerDrag);
mapEl.addEventListener("touchend", onTwoFingerDrag);
function onTwoFingerDrag (e) {
if (e.type === 'touchstart' && e.touches.length === 1) {
e.currentTarget.classList.add('swiping')
} else {
e.currentTarget.classList.remove('swiping')
}
}
It checks if the type is a touchevent and if you are using 1 finger, if so it adds the class to the map with the message. If you use more than one finger it removes the class.
Working demo I suggest you using a mobile device.
Code pen from the demo

Mobile Page Slider content with dynamic height

I am trying to implement the app that have 4 pages in 4 table. It supposed to be support swipe gesture, and each page contains dynamic data and make the pages have different height.
I tried to use responsive-slider-div-span.source example and integrate the 4 table into the slides.
I would like to set the width and height for the slides dynamically while the document ready, However, The slide will not show if the width and height is not pre set in the the slide div.
May I know any suggestion?
Typically, the size of jssor slider is defined in html code, and you can alter the size grammatically.
Given a slider at size 600x300, you can use javascript to change size before initialization of jssor slider.
<script>
jQuery(document).ready(function ($) {
var options = {};
//retrieve height of the slider, assuming the height should be 200px;
$("#slider1_container").height("200px");
$("#slider1_slides").height("200px");
var jssor_slider1 = new $JssorSlider$("slider1_container", options);
//According to your comment, please add following code
//Handle $EVT_PARK event BEGIN
function OnSliderPark(slideIndex, fromIndex) {
if (slideIndex == 0 || slideIndex == jssor_slider1.$SlidesCount() - 1) {
//do something scroll page to top
}
}
jssor_slider1.$On($JssorSlider$.$EVT_PARK, OnSliderPark);
//Handle $EVT_PARK event END
});
</script>
<div id="slider1_container" style="... width: 600px; height: 300px; ...">
<div u="slides" id="slider1_slides" style="... width: 600px; height: 300px; ...">
...
</div>
</div>

D3 filtering data points

I'm implementing the classic mercator example (https://github.com/mbostock/d3/blob/master/examples/mercator/mercator.html), which I've changed to zoom into Afghanistan and to use only one custom slider. I'm reading in GeoJSON data of places where explosions have happened and the graph maps them all at load. I want to use the slider to view only a month of explosion points at a time but am having trouble filtering the results. I've tried several things based on posts in the Google group but fail to understand how to filter the data read in previously from 'explosions.json'. Thanks for the help!
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>IED Attacks in Afghanistan (2004-2009)</title>
<script type="text/javascript" src="../d3.v2.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../lib/jquery-ui/jquery-ui.min.js"></script>
<style type="text/css">
#import url("../lib/jquery-ui/jquery-ui.css");
body, .ui-widget {
font: 14px Helvetica Neue;
}
svg {
width: 960px;
height: 600px;
border: solid 1px #ccc;
background: #eee;
}
line {
stroke: brown;
stroke-dasharray: 4,2;
}
path {
fill: #ccc;
stroke: #fff;
}
div {
width: 960px;
}
</style>
</head>
<body>
<h3>IED Attacks in Afghanistan (2004-2009)</h3>
<script type="text/javascript">
// Create the Mercator Projection (Map)
var xy = d3.geo.mercator(),
path = d3.geo.path().projection(xy);
// Create the states variable
var states = d3.select("body")
.append("svg")
.append("g")
.attr("id", "states");
// Create the equator variable
var equator = d3.select("svg")
.append("line")
.attr("x1", "0%")
.attr("x2", "100%");
// Create the explosions variable
var explosions = d3.select("svg")
.append("g")
.attr("id","explosions");
// Load in the states & equator data from the file 'world-countries.json'
d3.json("world-countries.json", function(collection) {
states
.selectAll("path")
.data(collection.features)
.enter().append("path")
.attr("d", path)
.append("title")
.text(function(d) { return d.properties.name; });
equator
.attr("y1", xy([0, 0])[1])
.attr("y2", xy([0, 0])[1]);
});
// the variable that holds our translate, center on Afghanistan
var translate = xy.translate(); //create translation to center gride in different area
translate[0] = -1741;
translate[1] = 1487;
xy.translate(translate); // center
xy.scale(12000); //zoom in
// Load in the explosions data from the file 'explosions.json'
d3.json("explosions.json", function(collection) {
explosions
.selectAll("path") //make a path and attach data
.data(collection.features)
.enter().append("path")
.attr("d", path)
.style("stroke","red") //color the path points
.style("stroke-width",2) //size of point stroke
.attr("class","explosionpoint")
.append("title") //title is the 'name' field in the json file
.text(function(d) { return d.properties.name; });
});
</script>
<p></p>
<!-- Slider -->
<div id="scale"></div><p></p>
<script type="text/javascript">
$("#scale").slider({
min: 20040101, //min : 1/1/04
max: 20100101, //max: 1/1/10
value: 20060601, //default slider value
step: 100, // step is the allow increments the slider can move. 100 = one month
slide: function(event, ui) {
/* REMOVE ALL EXPLOSION PATHS EXCEPT FOR A PARTICULAR MONTH OR RELOAD WITH FILTERED RESULTS */
}
});
</script>
You'll need to post part or all of your explosions.json object for a concrete answer. However, something like this will filter a JSON if it's structured like {explosion1:{data1:true, data2:true}, explosion2:{data1:true, data2:false}}:
function filterJSON(json, key, value) {
var result = {};
for (var explosionIndex in json) {
if (json[explosionIndex][key] === value) {
result[explosionIndex] = json[explosionIndex];
}
}
return result;
}
(e.g. filterJSON(myjson, "data1", true) will give all explosions with data1:true)
This is not specific to d3.
Then you could use something like this for the d3-side of things:
explosions.data(myFilteredData).exit().remove(); // remove ones you don't want
explosions.enter().append("path")... // add back ones you do want
If I understand your application, it would actually be better to just toggle the visiblity attribute of the SVG elements.
var sliderrange = [20040101, 20040201]; //replace with code based on your slider
explosions.selectAll(".explosionpoint").attr("visibility", function(d) {
//Replace with the correct date comparison logic
return d.date < sliderrange[1] && d.date > sliderrange[0] ? "visible" : "hidden";
});
D3 does have a very natural way of doing this. I'll assume your data looks something like this:
[{name: explosion1name, day: 20040110,...}, {name: explosion2name, day: 20040111,...}]
...and that you've got some variable, we'll call it explosionsData, to reference the data.
You can then draw your explosions with a function that takes the values from your slider. See the .filter I've added below.
function drawExplosions(startDay, endDay) {
explosions.selectAll("path") //make a path and attach data
.data(collection.features)
.enter().append("path")
.filter( function (d) { return ( (d.day > startDay) && (d.day < endDay) )})
.attr("d", path)
.style("stroke","red") //color the path points
.style("stroke-width",2) //size of point stroke
.attr("class","explosionpoint")
.append("title") //title is the 'name' field in the json file
.text(function(d) { return d.properties.name; });
Just call this function whenever your slider values changes.

Does codemirror provide Cut, Copy and Paste API?

From http://codemirror.net/doc/manual.html, I only find getRange(),
undo(), redo() etc, and I can't find cut(), copy() and paste API,
and more when I try to run editor.execCommand("cut"), I get the error.
Could you help me? Thanks!
Using clipboard.js, you can define the text() function to grab the value of the CodeMirror's inner document.
Store a reference to the (<textarea>) editor's selector for convenience.
var editorSelector = '#editor' // or '#editor + .CodeMirror';
Instantiate a new ClipBoard object with reference to your button.
new Clipboard('.clip-btn-native', {
text: function(trigger) {
return getCodeMirrorNative(editorSelector).getDoc().getValue();
}
});
Retrieve a CodeMirror Instance via native JavaScript.
function getCodeMirrorNative(target) {
var _target = target;
if (typeof _target === 'string') {
_target = document.querySelector(_target);
}
if (_target === null || !_target.tagName === undefined) {
throw new Error('Element does not reference a CodeMirror instance.');
}
if (_target.className.indexOf('CodeMirror') > -1) {
return _target.CodeMirror;
}
if (_target.tagName === 'TEXTAREA') {
return _target.nextSibling.CodeMirror;
}
return null;
};
Demo
Please see complete; in-depth demo over at JSFiddle.
There are no CodeMirror APIs for cut/copy/paste because browser security restrictions forbid JavaScript from accessing the clipboard programmatically. Paste could be used to steal private data and Cut/Copy can be used as a more elaborate attack vector.
The browser's own native code handles user gestures that access the clipboard (keyboard shortcuts and context menu items), based solely on the currently selected text or focused text field.
This SO thread has a good summary of attempts to work around these restrictions. CodeMirror's approach is the first bullet: it uses a hidden textarea to ensure that user clipboard gestures work, but that still doesn't support programmatic APIs.
But there is a partial workaround: use a small Flash widget (this is the 2nd bullet in the thread above). Flash relaxes the restrictions on Copy/Cut (but not Paste) a bit. It still has to be triggered by some user event, but it could be something like clicking a button in your HTML UI. Wrappers like ZeroClipboard and Clippy make it simple to access to these capabilities without needing to know Flash. You'd need to write a little glue code to pull the appropriate string from CodeMirror when copying, but it shouldn't be too bad.
Add a hidden contenteditable div to your textarea editor wrapper. Contenteditable divs respect new lines and tabs, which we need when copying code.
Here is my CodePen demo
var content = $('.content');
var toCopy = content.find('.copy-this');
// initialize the editor
var editorOptions = {
autoRefresh: true,
firstLineNumber: 1,
lineNumbers: true,
smartIndent: true,
lineWrapping: true,
indentWithTabs: true,
refresh: true,
mode: 'javascript'
};
var editor = CodeMirror.fromTextArea(content.find(".editor")[0], editorOptions);
content[0].editor = editor;
editor.save();
// set editors value from the textarea
var text = content.find('.editor').text();
editor.setValue(text);
// setting with editor.getValue() so that it respects \n and \t
toCopy.text(editor.getValue());
$(document).on('click', '.copy-code', function() {
var content = $(this).closest('.content');
var editor = content[0].editor;
var toCopy = content.find('.copy-this')[0];
var innerText = toCopy.innerText // using innerText here because it preserves newlines
// write the text to the clipboard
navigator.clipboard.writeText(innerText);
});
.content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.CodeMirror {
height: fit-content !important;
}
.copy-code {
background: #339af0;
width: fit-content;
cursor: pointer;
}
<!-- resources -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/codemirror.css" />
<script src="https://codemirror.net/lib/codemirror.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.40.0/mode/javascript/javascript.min.js"></script>
<script src=""></script>
<script src=""></script>
<script src=""></script>
<script src=""></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="content">
<!-- button to copy the editor -->
<div class="copy-code" title="copy code">copy</div>
<!-- add contenteditable div as it respects new lines when copying unlike textarea -->
<div class="copy-this" contenteditable style="display: none"></div>
<textarea class="editor" style="display: none;">// here is a comment
// here is another comment
</textarea>
</div>