How to run a function once in $ (window).scroll()? - scroll

I'm trying to make a page that launches different animation depending on the scroll.
The principle is simple, when I'm in a block with a data-attribute concerning the type of animation. I run this animation.
To do this, my script is based on the event $(window).scroll().
When my $(window).scrollTop() is equal to the position of my block, I run the animation. When I leave this block I stop the animation. I would like once the animation is complete, start once my reset function. Currently, she embarked loop as I am not in a block with a data-attribute.
A demo
I'm really stuck. Thank you in advance. Manu
my js file :
$(document).ready(init);
// Ma class Screen
function Screen(name){
this._name = $("#"+name);
this._hauteur;
this._position;
this._screenEnd;
this._screenEnd;
this.screenHeight = function() {
this._hauteur = this._name.data('height');
return this._hauteur;
}
this.topPosition = function() {
this._position = this._name.position().top;
return this._position;
}
this.screenEnd = function() {
this._screenEnd = (this._name.position().top)+(this._name.data('height'));
return this._screenEnd;
}
}
var mesScreens = new Array();
$(".screen").each(function(i){
mesScreens[i] = new Screen($(this).attr('id'));
mesScreens[i]._name.css("height", mesScreens[i].screenHeight());
//console.log(mesScreens[i]);
});
var fini = false;
function init(){
console.log($(".screen").length);
var scrollTimer = null;
$(window).scroll(function () {
var monScrollTop = $(window).scrollTop();
for (var i=0; i<mesScreens.length ; i++) {
if(monScrollTop>(mesScreens[i].topPosition()+5) && monScrollTop<=(mesScreens[i].screenEnd()+5)){
//started = true;
if(mesScreens[i]._name.data("func") == "panorama"){
horizontalPanel(mesScreens[i]._name, mesScreens[i]._hauteur, mesScreens[i]._position);
}else if(mesScreens[i]._name.data("func") == "anim"){
anim(mesScreens[i]._name, mesScreens[i]._hauteur, mesScreens[i]._position, 4);
}
//console.log(mesScreens[3]._hauteur);
}else {
//console.log("je sors");
reset(mesScreens[i]._name, mesScreens[i]._hauteur);
}
};
});
}
/*
* Function horizontalPanel
* #screen : le screen concerné
* #hauteur : hauteur du div
*/
function horizontalPanel(myScreen, hauteur, position){
//console.log("Fonction horizontalPanel debut || fini = "+fini);
var $img = myScreen.children("img");
var deltaScroll = ($(window).scrollTop() - position);
var scrollPercentage = ((deltaScroll / (hauteur)) * 100) ;
//console.log(scrollPercentage);
$img.css('position', "fixed");
$img.css("bottom", "");
$img.css('top', "0px");
$img.css('left', "0px");
$img.css("left", -scrollPercentage+"%");
}
function anim(myScreen, hauteur, position, nbImg){
//console.log("ok");
var $img = myScreen.children("div.image");
var deltaScroll = ($(window).scrollTop() - position);
var scrollPercentage = ((deltaScroll / (hauteur)) * 100) ;
var percentNb = ((nbImg/hauteur) * 100).toFixed(2);
for(var i=0; i<nbImg; i++){
//console.log("if(bla)");
}
//console.log("__");
if(scrollPercentage)
//console.log(hauteur);
$img.css('position', "fixed");
$img.css("top", "0px");
$img.css("bottom", "");
$img.css('background-position', "0 "+ scrollPercentage + '%');
$img.css('left', "0px");
}
function reset(myScreen){
//console.log("Fonction Reset || fini = "+fini);
myScreen.children().css('position', "relative");
myScreen.children().css("bottom", "0px");
myScreen.children().css("top", "");
myScreen.children().css("left", "");
}
An extract from html :
<div id="screen3" data-height='2300' data-func='panorama' class="screen">
<img src="img/screen3.jpg" alt="screen-3">
</div>
<div id="screen4">
<img src="img/screen4-2.jpg" alt="screen-4">
</div>

Related

html/css-/js drag and drop for mouse and touch combine with rotate with every click?

I use a script for moving an object both with mouse and touch screen. This works.
I have another script to make the object rotate 90 degrees with each click, this also works.
It just doesn't work together.
When I merge them, the move still works, but with a click the object moves back to the starting position and only rotates there.
I've read that I should merge this but I don't know how. Below both scripts.
Thanks in advance for responses.
var container = document.querySelector("#container");
var activeItem = null;
var active = false;
container.addEventListener("touchstart", dragStart, false);
container.addEventListener("touchend", dragEnd, false);
container.addEventListener("touchmove", drag, false);
container.addEventListener("mousedown", dragStart, false);
container.addEventListener("mouseup", dragEnd, false);
container.addEventListener("mousemove", drag, false);
function dragStart(e) {
if (e.target !== e.currentTarget) {
active = true;
// this is the item we are interacting with
activeItem = e.target;
if (activeItem !== null) {
if (!activeItem.xOffset) {
activeItem.xOffset = 0;
}
if (!activeItem.yOffset) {
activeItem.yOffset = 0;
}
if (e.type === "touchstart") {
activeItem.initialX = e.touches[0].clientX - activeItem.xOffset;
activeItem.initialY = e.touches[0].clientY - activeItem.yOffset;
} else {
console.log("doing something!");
activeItem.initialX = e.clientX - activeItem.xOffset;
activeItem.initialY = e.clientY - activeItem.yOffset;
}
}
}
}
function dragEnd(e) {
if (activeItem !== null) {
activeItem.initialX = activeItem.currentX;
activeItem.initialY = activeItem.currentY;
}
active = false;
activeItem = null;
}
function drag(e) {
if (active) {
if (e.type === "touchmove") {
e.preventDefault();
activeItem.currentX = e.touches[0].clientX - activeItem.initialX;
activeItem.currentY = e.touches[0].clientY - activeItem.initialY;
} else {
activeItem.currentX = e.clientX - activeItem.initialX;
activeItem.currentY = e.clientY - activeItem.initialY;
}
activeItem.xOffset = activeItem.currentX;
activeItem.yOffset = activeItem.currentY;
setTranslate(activeItem.currentX, activeItem.currentY, activeItem);
}
}
function setTranslate(xPos, yPos, el) {
el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
}
// Make blocks rotate 90 deg on each click
var count=0;
function rot(e){
count++;
var deg=count*90;
e.style.transform = "rotate("+deg+"deg)";
}
So I put them in a file but then it only works as described above.

How can I use round dots in my animated line in HTML5 canvas?

I am using line creation on HTML5 canvas to create two animated dashed paths, one after the other. I simply want to change the dashes to rounded dots.
I've seen setting context lineCap ='round', etc but it doesn't work
var canvas;
var ctx;
var pathColor="black";
function Vector(x, y)
{
this.X = x;
this.Y = y;
}
var m1, c1;
var pCount1=0;
var pCount2=0;
var pathInt = null;
var points1 = [new Vector(1400, 1500),new Vector(1365, 1495),new Vector(1330, 1490),new Vector(1295, 1485),new Vector(1260, 1480)];
var points2 = [new Vector(1280, 480),new Vector(1195, 470),new Vector(1110, 460),new Vector(1080, 450),new Vector(1000, 240),new Vector(1300, 140),new Vector(1580, 140),new Vector(1590, 180),];
function getClr() {
if(pathColor=="lightgrey") {
pathColor="black";
}
else {
pathColor="lightgrey";
}
}
window.onload = function()
{
m1 = document.querySelector("#b");
c1 = m1.getContext("2d");
pathInt = setInterval(function(){ pathTo(); }, 250);
};
function pathTo()
{
if(pCount1 <= points1.length && points1.length!=0)
{
c1.strokeStyle = pathColor;
c1.lineWidth = 15;
c1.setLineDash([25, 10]);
c1.beginPath();
c1.moveTo(points1[0].X, points1[0].Y);
for(var i = 0; i < pCount1; i++)
{
c1.lineTo(points1[i].X, points1[i].Y);
}
pCount1++;
c1.stroke();
}
else if(pCount2 <= points2.length && points2.length!=0)
{
c1.strokeStyle = pathColor;
c1.lineWidth = 15;
c1.setLineDash([25, 10]);
c1.beginPath();
c1.moveTo(points2[0].X, points2[0].Y);
for(var i = 1; i < pCount2; i++)
{
c1.lineTo(points2[i].X, points2[i].Y);
}
pCount2++;
c1.stroke();
pCount2++;
}
else {
clearInterval(pathInt);
setTimeout(function(){ redoPath(); }, 5000);
}
}
function redoPath() {
pCount1=0;
pCount2=0;
//c1.clearRect(0, 0, m1.width, m1.height);
getClr();
pathInt = setInterval(function(){ pathTo(); }, 250);
}
<canvas id="b" width="1746" height="1746" style="position:absolute;top:100px;left:50px;z-index:100;">
</canvas>
I know this must be possible, ..but not sure which properties I need to change. Any help is appreciated.

Ace Editor: Lock or Readonly Code Segment

Using the Ace Code Editor can I lock or make readonly a segment of code but still allow other lines of code to be written or edited during a session?
Here is the start of a solution:
$(function() {
var editor = ace.edit("editor1")
, session = editor.getSession()
, Range = require("ace/range").Range
, range = new Range(1, 4, 1, 10)
, markerId = session.addMarker(range, "readonly-highlight");
session.setMode("ace/mode/javascript");
editor.keyBinding.addKeyboardHandler({
handleKeyboard : function(data, hash, keyString, keyCode, event) {
if (hash === -1 || (keyCode <= 40 && keyCode >= 37)) return false;
if (intersects(range)) {
return {command:"null", passEvent:false};
}
}
});
before(editor, 'onPaste', preventReadonly);
before(editor, 'onCut', preventReadonly);
range.start = session.doc.createAnchor(range.start);
range.end = session.doc.createAnchor(range.end);
range.end.$insertRight = true;
function before(obj, method, wrapper) {
var orig = obj[method];
obj[method] = function() {
var args = Array.prototype.slice.call(arguments);
return wrapper.call(this, function(){
return orig.apply(obj, args);
}, args);
}
return obj[method];
}
function intersects(range) {
return editor.getSelectionRange().intersects(range);
}
function preventReadonly(next, args) {
if (intersects(range)) return;
next();
}
});
see it working in this fiddle: http://jsfiddle.net/bzwheeler/btsxgena/
The major working pieces are:
create start and end ace anchors which track the location of a 'readonly' portion as the document around it changes.
create a range to encapsulate the anchors
add a custom keyhandler to check if the current impending keypress will affect the readonly range and cancel it if so.
add custom paste/cut handlers to protect against right-click menu and browser menu cut/paste actions
You can do it by listening to the exec events:
// Prevent editing first and last line of editor
editor.commands.on("exec", function(e) {
var rowCol = editor.selection.getCursor();
if ((rowCol.row === 0) || ((rowCol.row + 1) === editor.session.getLength())) {
e.preventDefault();
e.stopPropagation();
}
});
Source: https://jsfiddle.net/tripflex/y0huvc1b/
I suggest something else easier and more reliable to prevent range to be modified (check it!)
var old$tryReplace = editor.$tryReplace;
editor.$tryReplace = function(range, replacement) {
return intersects(range)?null:old$tryReplace.apply(this, arguments);
}
var session = editor.getSession();
var oldInsert = session.insert;
session.insert = function(position, text) {
return oldInsert.apply(this, [position, outsideRange(position)?text:""]);
}
var oldRemove = session.remove;
session.remove = function(range) {
return intersects(range)?false:oldRemove.apply(this, arguments);
}
var oldMoveText = session.moveText;
session.moveText = function(fromRange, toPosition, copy) {
if (intersects(fromRange) || !outsideRange(toPosition)) return fromRange;
return oldMoveText.apply(this, arguments)
}
outsideRange = function (position) {
var s0 = range.start;
if (position.row < s0.row || (position.row == s0.row && position.column <= s0.column)) return true; // position must be before range.start
var e0 = range.end;
if (position.row > e0.row || (position.row == e0.row && position.column >= e0.column)) return true; // or after range.end
return false;
}
intersects = function(withRange) {
var e = withRange.end, s0 = range.start, s = withRange.start, e0 = range.end;
if (e.row < s0.row || (e.row == s0.row && e.column <= s0.column)) return false; // withRange.end must be before range.start
if (s.row > e0.row || (s.row == e0.row && s.column >= e0.column)) return false; // or withRange.start must be after range.end
return true;
}

Set selection on tekst inside CKEditor

I'm having trouble to select text in CKEditor(3.6). As we use plain text i dont know how to use correctly the range selectors.
HTML code of the CKEditor:
<body spellcheck="false" class="rf-ed-b" contenteditable="true">
<br>
Cross those that apply:<br>
<br>
<br>
[«dummy»] If he/she is tall<br>
<br>
[«dummy»] If he/she is a male<br>
<br>
[«dummy»] If he/shi is a minor<br>
<br>
Specialties:<br>
<br>
[«dummy»] «Write here the specialties if known»<br>
<br>
<br>
«You are now done with filling in this form»<br>
</body>
With the keys 'CRTL+N' I want to go to the next filleble spot:
«[label]»
I tried stuff like:
var editor = CKEDITOR.instances['MyEditor'];
var findString = '«';
var element = editor.document.getBody();
var ranges = editor.getSelection().getRanges();
var startIndex = element.getHtml().indexOf(findString);
if (startIndex != -1) {
ranges[0].setStart(element.getFirst(), startIndex);
ranges[0].setEnd(element.getFirst(), startIndex + 5);
editor.getSelection().selectRanges([ranges[0]]);
}
Error:
Exception: Index or size is negative or greater than the allowed amount
While totally stripepd down it kinda works a bit:
var editor = CKEDITOR.instances['MyEditor'];
var ranges = editor.getSelection().getRanges();
var startIndex = 10;
if (startIndex != -1) {
ranges[0].setStart(element.getFirst(), startIndex);
ranges[0].setEnd(element.getFirst(), startIndex + 5);
editor.getSelection().selectRanges([ranges[0]]);
}
here it selects 5th till 10th char on first row.
I used the following sources:
example on Stackoverflow
Another stackoverflow example
CKEditor dom selection API
All solutions i can find work with html nodes.
How can set selection range on the '«' till next '»'
I've managed to solve this solution. Meanwhile i also upgraded CKeditor to 4.0.
This shouldnt have an impact on the solution.
It is a lot of code in JS.
On my keybinding i call the following JS function: getNextElement()
In this solution it also searches behind the cursor, this makes it possible to step through multiple find results.
Also the view gets scrolled to the next search result
var textNodes = [], scrollTo=0,ranges = [];
function getNextElement(){
var editor =null;
ranges = [];
// I dont know the ID of the editor, but i know there is only one the page
for(var i in CKEDITOR.instances){
editor = CKEDITOR.instances[i];
}
if(editor ==null){
return;
}
editor.focus();
var startRange = editor.getSelection().getRanges()[0];
var cursorData ="",cursorOffset=0,hasCursor = false;
if(startRange != null && startRange.endContainer.$.nodeType == CKEDITOR.NODE_TEXT){
cursorOffset = startRange.startOffset;
cursorData = startRange.endContainer.$.data;
hasCursor = true;
}
var element;
element = editor.document.getBody().getLast().getParent();
var selection = editor.getSelection();
// Recursively search for text nodes starting from root.
textNodes = [];
getTextNodes( element );
var foundElement = false;
foundElement = iterateEditor(editor,hasCursor,cursorData,cursorOffset);
if(!foundElement){
foundElement =iterateEditor(editor,false,"",0);
}
if(foundElement){
// Select the range with the first << >>.
selection.selectRanges( ranges );
jQuery(".cke_wysiwyg_frame").contents().scrollTop(scrollTo);
}
}
function iterateEditor(editor,hasCursor,cursorData,cursorOffset){
var foundElement = false;
var rowNr = 0;
var text, range;
var foundNode = false;
if(!hasCursor){
foundNode = true;
}
// Iterate over and inside the found text nodes. If some contains
// phrase "<< >>", create a range that selects this word.
for (var i = textNodes.length; i--; ) {
text = textNodes[ i ];
if ( text.type == CKEDITOR.NODE_ELEMENT && text.getName() == "br" ){
rowNr++;
} else if ( text.type == CKEDITOR.NODE_TEXT ) {
var sameNode = false;
if(text.$.data == cursorData){
foundNode = true;
sameNode = true;
}
if(foundNode){
var startIndex = -1;
var endIndex = 1;
if(sameNode){
// Check inside the already selected node if the text has multiple hits on the searchphrase
var indicesStart = getIndicesOf('\u00AB', text.getText());
var indicesEnd = getIndicesOf('\u00BB', text.getText());
for (var j = indicesStart.length; j--; ) {
if(indicesStart[j] > cursorOffset){
startIndex = indicesStart[j];
endIndex = indicesEnd[j];
}
}
} else{
startIndex = text.getText().indexOf( '\u00AB' );
endIndex = text.getText().indexOf( '\u00BB' );
}
if ( startIndex > -1 && (!sameNode || startIndex > cursorOffset)) {
range = editor.createRange();
range.setStart( text, startIndex );
foundElement = true;
// calculate the height the window should scroll to focus the selected element
scrollTo = (rowNr)*20;
}
if ( endIndex > -1 && foundElement ) {
range.setEnd( text, endIndex+1 );
ranges.push( range );
return true;
}
}
}
}
}
function getIndicesOf(searchStr, str) {
var startIndex = 0, searchStrLen = searchStr.length;
var index, indices = [];
while ((index = str.indexOf(searchStr, startIndex)) > -1) {
indices.push(index);
startIndex = index + searchStrLen;
}
return indices;
}
function getTextNodes( element ) {
var children = element.getChildren(), child;
for ( var i = children.count(); i--; ) {
child = children.getItem( i );
textNodes.push( child );
}
}

Flash AS2 - grouping enemies

So I have a Flash ActionScript 2 code, which creates a preset amount of enemies, gives enemies stats, and makes them move around randomly. Code:
//Settings
var mapWidth:Number = 550;
var mapHeight:Number = 400;
var enemiesArray:Array = new Array();
var totalEnemies:Number;
var eClip:MovieClip;
//Math functions
function getdistance(x, y, x1, y1)
{
run = x1-x;
rise = y1-y;
return (hyp(run, rise));
}
function hyp(a, b)
{
return (Math.sqrt(a*a+b*b));
}
function resetDirection(mc:MovieClip)
{
mc.roamTime = random(50);
mc.t = mc.roamTime;
mc.roamDistance = random(60)+25;
mc.randomRoamDistanceX = (Math.random()*mc.roamDistance)+mc.xx-(mc.roamDistance/2);
mc.randomRoamDistanceY = (Math.random()*mc.roamDistance)+mc.yy-(mc.roamDistance/2);
mc.newRoamDistance = getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY);
mc.norm = mc.roamSpeed/mc.newRoamDistance;
mc.finalRoamDistanceX = (mc.randomRoamDistanceX-mc.xx)*mc.norm;
mc.finalRoamDistanceY = (mc.randomRoamDistanceY-mc.yy)*mc.norm;
}
//function to move enemies
function moveIt(mc:MovieClip)
{
//reduce roamTime;
mc.t--;
//move enemy to new position
if (getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY)>mc.roamSpeed) {
mc._x += mc.finalRoamDistanceX;
mc._y += mc.finalRoamDistanceY;
}
//rotate enemy
XXXdiff = mc.xx-mc.randomRoamDistanceX;
YYYdiff = -(mc.yy-mc.randomRoamDistanceY);
rrradAngle = Math.atan(YYYdiff/XXXdiff);
if (XXXdiff<0) {
cccorrFactor = 270;
} else {
cccorrFactor = 90;
}
//
mc.ship_mc._rotation = -(rrradAngle*360/(2*Math.PI)+cccorrFactor);
//check if time to reset, based on roamTime
if (mc.t<=0) {
resetDirection(mc);
}
}
//
// Generate Enemies
//
// set and save enemy stats
//
//
// createEnemies(number of enemies you want, movieclip where you want to create the enemies);
//
function createEnemies(amount:Number, targetLocation:MovieClip) {
trace("createEnemies: "+amount);
for (var i = 0; i<amount; i++) {
randomXpos = Math.round(Math.random()*mapWidth);
randomYpos = Math.round(Math.random()*mapHeight);
//add new enemy to map
var newEnemy:MovieClip = targetLocation.attachMovie("enemy1", "enemy1_"+i, targetLocation.getNextHighestDepth());
enemiesArray.push(newEnemy);
//
//set enemy stats
newEnemy.id = i;
newEnemy._x = randomXpos;
newEnemy._y = randomYpos;
//save x and y position
newEnemy.xx = newEnemy._x;
newEnemy.yy = newEnemy._y;
//
newEnemy.roamSpeed = 2
newEnemy.roamTime = random(50);
newEnemy.roamDistance = random(60)+25;
newEnemy.t = 0;
//
newEnemy.myHealth = 10;
newEnemy.myName = "Small Scout";
//
resetDirection(newEnemy);
//target enemy
newEnemy.onPress = function() {
trace("Enemy: "+this.tName+" "+this.id);
target_txt.text = this.myName+": "+this.id+" Health: "+this.myHealth;
};
newEnemy.onEnterFrame = function() {
moveIt(this);
};
}
}
start_btn.onRelease = function() {
if (start_txt.text == "Start") {
//run the create enemies function to start the engine
createEnemies(box_mc.numberOfEnemies.text, map_mc);
//hide start button
start_txt._visible =false;
this._visible = false;
box_mc._visible = false;
}
};
I want program enemies to be grouped (based on fireflies algorithm). My idea is write for loop to define attractiveness, but I don't know how to make my objects move to the most attractiveness. Maybe someone would help me with this problem?
I change this line:
newEnemy.myHealth = 10;
on this
newEnemy.myHealth = Math.round(random(9)+1);
myHealth would be responsible for attractiveness. I try to use code from this site and modificate code to let objects with low attractiveness follow objects with large attractiveness. Also, I want to stop algorith, when they are in the groups.

Resources