Add non-click function inside of a click function - javascript

I have the following problem. I have a .one("click") function with a variable that raises itself, and I need to add a function, that triggers, when the variable hits the wanted point. I mean, in the following code I need to use the connect function for the last 'last' img with the 'home' img, after the Result variable turns 9, which will produce a line between them, and I'll have a complete circle. Please read the code and try clicking on all img-es so that you can understand, what i need to achieve. Thanks in advance.
Here's the code:
$(document).ready(function() {
var Result = 0;
$('img').one("click", function(){
if( $('img.home').length == 0 ){
$(this).addClass('home');
}
if(Result <= 9){
var $elem2 = $('span.last');
var $elem1 = $(this).parent();
$(this).toggleClass('selected');
if ($elem2.length > 0) {
connect($elem1[0], $elem2[0], "#0F0", 5);
}
else {
$elem1.addClass('last');
}
$('span').removeClass('last');
$elem1.addClass('last');
Result++;
}
});
});
function connect(div1, div2, color, thickness) {
var off1 = getOffset(div1);
var off2 = getOffset(div2);
// bottom right
var x1 = off1.left + off1.width;
var y1 = off1.top + off1.height;
// top right
var x2 = off2.left + off2.width;
var y2 = off2.top;
// distance
var length = Math.sqrt(((x2-x1) * (x2-x1)) + ((y2-y1) * (y2-y1)));
distanz += parseInt(length);
// center
var cx = ((x1 + x2) / 2) - (length / 2);
var cy = ((y1 + y2) / 2) - (thickness / 2);
// angle
var angle = Math.atan2((y1-y2),(x1-x2))*(180/Math.PI);
// make hr
var htmlLine = "<div style='padding:0px; margin:0px; height:" + thickness + "px; background-color:" + color + "; line-height:1px; position:absolute; left:" + cx + "px; top:" + cy + "px; width:" + length + "px; -moz-transform:rotate(" + angle + "deg); -webkit-transform:rotate(" + angle + "deg); -o-transform:rotate(" + angle + "deg); -ms-transform:rotate(" + angle + "deg); transform:rotate(" + angle + "deg);' />";
htmlLine = $(htmlLine);
$('body').append(htmlLine);
return htmlLine;
}
function getOffset( el ) {
var x = 0;
var y = 0;
var w = el.offsetWidth|0;
var h = el.offsetHeight|0;
while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
x += el.offsetLeft - el.scrollLeft;
y += el.offsetTop - el.scrollTop;
el = el.offsetParent;
}
return { top: y, left: x, width: w, height: h };
}
jsfiddle: http://jsfiddle.net/CDQhX/4/
I want to execute the connect(home and span images) after the last line is done and the Result is 9. This can't be done inside the click function, since I'm not clicking anywhere to trigger it. My knowledge don't let me work the problem around. So I appreciate any help. I'll be really glad to receive answers.

First of all, what do you mean you are not clicking anywhere and you want it executed when the last img is clicked. Can't you just check if the img is last when it is clicked, and execute what you need?
Also, on the other hand, you can try setTimeout and setInterval as described here: http://www.w3.org/TR/2011/WD-html5-20110525/timers.html
So, for example, you could do something like this:
setInterval( function() {
//do your thing
}, 500);
Which will execute the function every 500 milliseconds, so you could use that for periodic checking of your variables.

Related

The if condition only works with an alert and the position is reset?

The code is that the player goes to where the user clicks, but now I want the character to look at the X axis where it goes.
The problem is that it only works when you have an alert, but only if the alert gives an error because if the alert does not give an error it does not work.
The other problem is that the transform translate3d is deleted then the player returns to the same position although the scaleX changes.
I'm new to jquery and I have no idea.
$(document).on("click mousedown", "#Park", function(e) {
var x = e.clientX;
var y = e.clientY;
var newposX = x - 60;
var newposY = y - 60;
var n = $(".circle").offset()
if (newposX < n.left) {
$(".circle").css("transform", "scaleX(-1)");
alert(ok)
}
$(".circle").css("transform", "translate3d(" + newposX + "px," + newposY + "px,0px)");
setTimeout(function() {
$(".circle3").css("display", "none");
$(".circle2").css("display", "block");
}, 2000);
$(".circle2").css("display", "none");
$(".circle3").css("display", "block");
});
Immediately after the conditional, you're overwriting the transform with a new value, which means the scaleX() is immediately overwritten unless your code breaks at the alert().
Instead, write your conditional like this, to ensure the scaleX() doesn't get overwritten when you set the translate3d():
if (newposX < n.left) {
$(".circle").css("transform", "scaleX(-1) translate3d(" + newposX + "px," + newposY + "px,0px)");
} else {
$(".circle").css("transform", "translate3d(" + newposX + "px," + newposY + "px,0px)");
}
Alternatively, you could write it like this, which is easier to read in my opinion:
let transform = `translate3d(${newposX}px, ${newposY}px, 0px)`;
if (newposX < n.left) {
transform = 'scaleX(-1) ' + transform;
}
$('.circle').css('transform', transform);

On mousemove translate div position within a specified range

I have a wrapper called #mousearea and I have a div called #mouseshift what I would like to do is when I hover over #mousearea I would like to shift the translate3d(0,230%,0) value between a particular range.
I have got the mousemove working but I currently end up with something like translate3d(7881%,230%,0) it's just too sensetive I would like it to translate the X co-ordinate between something like 0-60% so it's far more subtle.
Here is what I have so far:
jQuery(document).ready(function($){
$('#mousearea').mousemove(function (e) {
var shiftAmount = 1;
$('#mouseshift').css(
'transform', 'rotate(90deg) translate3d(' + -e.pageY + shiftAmount + '%,230%,0)'
);
});
});
Update:
This is a little closer, except it logs the correct translate3d but doesn't apply it to #mouseshift.
$('#mousearea').mousemove(function(e){
var x = e.pageY - this.offsetTop;
var transfromPosition = 'translate3d(' + x + ', 230%, 0)';
console.log(transfromPosition);
if ((x <= 800)) {
//$('#mouseshift').css({'top': x});
$('#mouseshift').css('transform', transfromPosition);
}
});
Final Solution:
jQuery(document).ready(function($){
$('#mousearea').mousemove(function(e){
var min = 50;
var max = 70;
var x = e.pageY;
var windowHeight = window.innerHeight;
scrolled = (x / windowHeight);
percentageScrolled = scrolled * 100;
offsetScroll = max - min;
offsetPercentage = scrolled * 20;
translateX = min + offsetPercentage;
console.log(x + 'px');
console.log(windowHeight + 'px window height');
console.log(percentageScrolled + '% scrolled');
console.log(offsetScroll + 'offset scroll');
console.log(offsetPercentage + '% offset percentage');
var transfromPosition = 'rotate(90deg) translate3d(' + translateX + '%, 230%, 0)';
$('#mouseshift h1').css('transform', transfromPosition);
});
});
Convert to a reusable plugin I would like to extend this to work with more than one object now and each object would have a different max and min value:
This is what I have but it seems to effect all the items on only use on elements max and min.
$(function () {
$('#mouseshift-1, #mouseshift-2').mouseShift();
});
(function ($) {
$.fn.mouseShift = function () {
return this.each(function () {
var myEl = $(this);
var min = $(this).data('min');
var max = $(this).data('max');
$('#mousearea').mousemove(function (e) {
var yPosition = e.pageY;
var windowHeight = window.innerHeight;
scrolled = (yPosition / windowHeight);
//percentageScrolled = scrolled * 100;
offsetRange = max - min;
offsetRangePercentage = scrolled * 20;
offset = min + offsetRangePercentage;
//// Debug
console.log('max: ' + max + ', Min:' + min);
console.log(yPosition + 'px');
console.log(windowHeight + 'px window height');
//console.log(percentageScrolled + '% scrolled');
console.log(offsetRange + 'px offset scroll');
console.log(offsetRangePercentage + '% offset percentage');
var transfromPosition = 'rotate(90deg) translate3d(' + offset + '%, 230%, 0)';
myEl.css('transform', transfromPosition);
});
});
};
})(jQuery);
And some HTML for clarity:
<div class="column"><h1 id="mouseshift-1" data-min="50" data-max="70">boo</h1></div>
<div class="column"><h1 id="mouseshift-2" data-min="20" data-max="90">bah</h1></div>
<div class="column"><h1 id="mouseshift-3" data-min="80" data-max="100">bing</h1></div>
I think what you are looking for is finding an average that your can distribute. The best way to do this is to divide by the maximum amount it can move, and multiply it by the maximum value it can have, so basically:
position / maxposition * maxvalue
The first bit will return a number between 0 and 1, while the last bit will make it the value between 0 and 60. Below I have built a simply (jquery-less) version of it to show how this would work:
var mousePointer = document.getElementById('test')
document.addEventListener('mousemove', function(e){
var x = e.pageX / window.innerHeight;
x = x * -60;
mousePointer.style.webkitTransform = 'translateX(' + x + '%)';
mousePointer.style.transform = 'translateX(' + x + '%)';
})
#test {
position: absolute;
left: 50%;
top: 50%;
width: 20px;
height: 20px;
background: red;
}
<div id="test"></div>
Update: Reusable Snippet
I don't really like using jQuery, so once again it will be vanilla javascript (but it's pretty simple). Is that what you were - sort of - trying to do with the reusable plugin?
var divs = Array.prototype.slice.call(document.querySelectorAll('[data-range]'));
document.addEventListener('mousemove', function(e){
var eased = e.pageX / window.innerWidth;
divs.forEach(function(div){
var range = div.getAttribute('data-range').split(',');
var min = parseFloat(range[0]);
var max = parseFloat(range[1]);
var ease = min + (eased * (max - min));
div.style.webkitTransform = 'translateX(' + ease + '%)';
div.style.transform = 'translateX(' + ease + '%)';
});
});
div {
position: absolute;
left: 50%;
top: 50%;
width: 200px;
height: 200px;
background: gray;
}
#d2 { background: yellow; }
#d3 { background: #666; }
<div data-range="60,70" id="d1"></div>
<div data-range="-70,70" id="d2"></div>
<div data-range="-60,-70" id="d3"></div>
From simple reading, I see that you're missing a % sign. Should be like this:
$('#mousearea').mousemove(function(e){
var x = e.pageY - this.offsetTop;
var transfromPosition = 'translate3d(' + x + '%, 230%, 0)';
console.log(transfromPosition);
if ((x <= 800)) {
//$('#mouseshift').css({'top': x});
$('#mouseshift').css('transform', transfromPosition);
}
});
This should be working like your first example, where you do use % for both values inside the translate3d string.
Update:
To coerce your x Value to something between 0 and 60, you need to find a pair of possible min and max values for x. Then you can do something like what's shown in this answer:
Convert a number range to another range, maintaining ratio

define start to finish positions

I am creating a new "whack-a-mole" style game where the children have to hit the correct numbers in accordance to the question. So far it is going really well, I have a timer, count the right and wrong answers and when the game is started I have a number of divs called "characters" that appear in the container randomly at set times.
I have been given a theme of bubbles so they want me to make the "characters" start at the bottom and animate upwards. Any ideas how I would achieve this?
Here is the code that currently maps the divs to there positions in the canvas...
function moveRandom(id) {
var cPos = $('#container').offset();
var cHeight = $('#container').height();
var cWidth = $('#container').width();
var pad = parseInt($('#container').css('padding-top').replace('px', ''));
var bHeight = $('#' + id).height();
var bWidth = $('#' + id).width();
maxY = cPos.top + cHeight - bHeight - pad;
maxX = cPos.left + cWidth - bWidth - pad;
minY = cPos.top + pad;
minX = cPos.left + pad;
newY = randomFromTo(minY, maxY);
newX = randomFromTo(minX, maxX);
$('#' + id).css({
top: newY,
left: newX
}).fadeIn(1000, function() {
setTimeout(function() {
$('#' + id).fadeOut(1000);
window.cont++;
}, 7000);
});
Here is my most recent fiddle: http://jsfiddle.net/pUwKb/15/
The part below actually set the CSS (and thus the position of your element).
$('#' + id).css({
top: newY,
left: newX }).fadeIn(1000, function() {
setTimeout(function() {
$('#' + id).fadeOut(1000);
window.cont++;
}, 7000); });
You should add a function move who uses a movement variable. Small example:
function move(movement, id) {
$('#' + id).css({
top: this.css('top') + movement.y,
left: this.css('left') + movement.x
}).fadeIn(1000, function() {
setTimeout(function() {
$('#' + id).fadeOut(1000);
window.cont++;
}, 7000);
});
}
Where in movement should be an object something the like of {x: 30, y: 0} which would result in a 30 pixels movement to the right. Hope it helps!

Can I draw a line using jQuery?

I have a web app where I would like the user to draw a line in the following way: When he clicks on Point1 and he moves the mouse, draw the line from Point1 to the current mouse position and, when clicks to Point2 draw the final line from Point1 to Point2.
How can I do it using jQuery and/or one of its plugins?
Challenge accepted.
I tried to do it with CSS transforms and a bunch of Math in Javascript - after half an hour I have this:
http://jsfiddle.net/VnDrb/2/
Make 2 clicks into the gray square and a line should be drawn.
There is still a small bug that draws the line wrong when the angle is > 45 degree. Maybe someone else knows how to fix that. Maybe instead of using Math.asin (arcsinus), use a other trigonometrical function, but I'm really not good at it.
I thought I'd post it even there is a small bug, I think it's a good start for you.
I've tried a number of different approaches this weekend and the solution that worked best for me is from Adam Sanderson: http://monkeyandcrow.com/blog/drawing_lines_with_css3/
His demo is here: http://monkeyandcrow.com/samples/css_lines/
The core of it is very simple, which is always good.
div.line{
transform-origin: 0 100%;
height: 3px; /* Line width of 3 */
background: #000; /* Black fill */
}
function createLine(x1,y1, x2,y2){
var length = Math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
var angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
var transform = 'rotate('+angle+'deg)';
var line = $('<div>')
.appendTo('#page')
.addClass('line')
.css({
'position': 'absolute',
'transform': transform
})
.width(length)
.offset({left: x1, top: y1});
return line;
}
You can not do it with jQuery and classic HTML.
You can do it using SVG (+svgweb for IE8- http://code.google.com/p/svgweb/ )
SVG can be dynamically created. jQuery + svgweb are working perfectly, you just need to know how to create SVG nodes and you need only jquerify this nodes. After jquerifiing in most cases used only one method attr()
You can do it using Raphael http://raphaeljs.com/ (based on SVG and VML)
You can do it using Canvas ( http://flashcanvas.net/ for IE8- )
For SVG programming will be this way:
Moment of creating first point: you create empty line var Line (also this points coordinates will be x1 and y1)
Then you bind on mousemove repaint of x2, y2 properties of Line
On mousedown after mousemove you freeze last line position.
UPDATE
You can do it with CSS/JS, but main problem is in calculations for IE8-, that has only Matrix filter for transformations.
Been using a modified version of this for a while now. Works well.
http://www.ofdream.com/code/css/xline2.php
So on first click, drop and object there as a placeholder div, maybe a little circle, then either keep redrawing a line as they move their mouse, or draw it when they click the second time, using the original placeholder as a guide.
I recently made another helper function for this, because my tool involves moving lines around:
function setLinePos(x1, y1, x2, y2, id) {
if (x2 < x1) {
var temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
var line = $('#line' + id);
var length = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
line.css('width', length + "px");
var angle = Math.atan((y2 - y1) / (x2 - x1));
line.css('top', y1 + 0.5 * length * Math.sin(angle) + "px");
line.css('left', x1 - 0.5 * length * (1 - Math.cos(angle)) + "px");
line.css('-moz-transform', "rotate(" + angle + "rad)");
line.css('-webkit-transform', "rotate(" + angle + "rad)");
line.css('-o-transform', "rotate(" + angle + "rad)");
}
That is the jquery version, and in this iteration I have no IE requirement so I ignore it. I could be adapted from the original function pretty easily.
The class
function getXY(evt, element) {
var rect = element.getBoundingClientRect();
var scrollTop = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
var scrollLeft = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft;
var elementLeft = rect.left + scrollLeft;
var elementTop = rect.top + scrollTop;
x = evt.pageX - elementLeft;
y = evt.pageY - elementTop;
return { x: x, y: y };
}
var LineDrawer = {
LineHTML: `<div style="cursor: pointer;transform-origin:center; position:absolute;width:200px;height:2px; background-color:blue"></div>`,
isDown: false,
pStart: {},
pCurrent :{},
containerID: "",
JLine: {},
angle: 0,
afterLineCallback: null,
Init: function (containerID, afterLineCallback) {
LineDrawer.containerID = containerID;
LineDrawer.afterLineCallback = afterLineCallback;
LineDrawer.JLine = $(LineDrawer.LineHTML).appendTo("#" + LineDrawer.containerID);
LineDrawer.JLine.css("transform-origin", "top left");
LineDrawer.JLine.hide();
//LineDrawer.JLine.draggable({ containment: "#" + LineDrawer.containerID });
$("#" + LineDrawer.containerID).mousedown(LineDrawer.LineDrawer_mousedown);
$("#" + LineDrawer.containerID).mousemove(LineDrawer.LineDrawer_mousemove);
$("#" + LineDrawer.containerID).mouseup(LineDrawer.LineDrawer_mouseup);
},
LineDrawer_mousedown: function (e) {
if (e.target === LineDrawer.JLine[0]) return false;
LineDrawer.isDown = true;
let p = LineDrawer.pStart = getXY(e, e.target);
LineDrawer.JLine.css({ "left": p.x, "top": p.y, "width": 1});
LineDrawer.JLine.show();
},
LineDrawer_mousemove: function (e) {
if (!LineDrawer.isDown) return;
LineDrawer.pCurrent = getXY(e, document.getElementById("jim"));
let w = Math.sqrt(((LineDrawer.pStart.x - LineDrawer.pCurrent.x) * (LineDrawer.pStart.x - LineDrawer.pCurrent.x)) + ((LineDrawer.pStart.y - LineDrawer.pCurrent.y) * (LineDrawer.pStart.y - LineDrawer.pCurrent.y)));
LineDrawer.JLine.css("width", w - 2);
LineDrawer.angle = Math.atan2((LineDrawer.pStart.y - LineDrawer.pCurrent.y), (LineDrawer.pStart.x - LineDrawer.pCurrent.x)) * (180.0 / Math.PI);
//the below ensures that angle moves from 0 to -360
if (LineDrawer.angle < 0) {
LineDrawer.angle *= -1;
LineDrawer.angle += 180;
}
else LineDrawer.angle = 180 - LineDrawer.angle;
LineDrawer.angle *= -1;
LineDrawer.JLine.css("transform", "rotate(" + LineDrawer.angle + "deg");
},
LineDrawer_mouseup: function (e) {
LineDrawer.isDown = false;
if (LineDrawer.afterLineCallback == null || LineDrawer.afterLineCallback == undefined) return;
LineDrawer.afterLine(LineDrawer.angle, LineDrawer.pStart, LineDrawer.pCurrent);
},
};
Usage:
var ECApp = {
start_action: function () {
LineDrawer.Init("jim", ECApp.afterLine);
},
afterLine(angle, pStart, pEnd) {
//$("#angle").text("angle : " + angle);
let disp = "angle = " + angle;
disp += " Start = " + JSON.stringify(pStart) + " End = " + JSON.stringify(pEnd);
//alert(disp);
$("#angle").text("angle : " + disp);
}
}
$(document).ready(ECApp.start_action);
HTML
<div class="row">
<div class="col">
<div id="jim" style="position:relative;width:1200px;height:800px;background-color:lightblue;">
</div>
</div>

How to draw a line between two divs?

I'm currently trying to draw a diagonal line between the bottom right corner of one div to the top right corner of another. If possible, I would like to do it without jQuery. Is this possible?
http://jsfiddle.net/cnmsc1tm/
This won't work with IE8 or below because of CSS limitations.
function getOffset( el ) {
var rect = el.getBoundingClientRect();
return {
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight
};
}
function connect(div1, div2, color, thickness) { // draw a line connecting elements
var off1 = getOffset(div1);
var off2 = getOffset(div2);
// bottom right
var x1 = off1.left + off1.width;
var y1 = off1.top + off1.height;
// top right
var x2 = off2.left + off2.width;
var y2 = off2.top;
// distance
var length = Math.sqrt(((x2-x1) * (x2-x1)) + ((y2-y1) * (y2-y1)));
// center
var cx = ((x1 + x2) / 2) - (length / 2);
var cy = ((y1 + y2) / 2) - (thickness / 2);
// angle
var angle = Math.atan2((y1-y2),(x1-x2))*(180/Math.PI);
// make hr
var htmlLine = "<div style='padding:0px; margin:0px; height:" + thickness + "px; background-color:" + color + "; line-height:1px; position:absolute; left:" + cx + "px; top:" + cy + "px; width:" + length + "px; -moz-transform:rotate(" + angle + "deg); -webkit-transform:rotate(" + angle + "deg); -o-transform:rotate(" + angle + "deg); -ms-transform:rotate(" + angle + "deg); transform:rotate(" + angle + "deg);' />";
//
// alert(htmlLine);
document.body.innerHTML += htmlLine;
}
The Distance Formula
Finding the Center Of Two Points
Finding the Angle Between Two Points
CSS Transform:Rotate
HTML Element offset[Width|Height|Top|Left] properties
Edit (for others with the same problem):
If you need to, for example, create a line from two corners that are not the top right and bottom right divs, go to this section of the code:
// bottom right
var x1 = off1.left + off1.width;
var y1 = off1.top + off1.height;
// top right
var x2 = off2.left + off2.width;
var y2 = off2.top;
where you see + off1.width and + off1.height, that means that the code is calculating the position of the bottom or the right of the div. Remove the + off1.width or the + off1.height to get the left or the top of the div.
EDIT updated to a more standard getOffset function. If you want to get really anal you'd probably also have to add document.documentElement.client[Left/Top] and walk the offsetParent tree, but I think getBoundingClientRect() and window.page[X/Y]Offset are sufficient for an example like this.
There is a way to do it without jQ.
Find the position of your divs using offset.
Find the slope
draw 1x1px points from start to end position using the slope in your loop.

Categories

Resources