This javascript fails on mouseover - javascript
can anyone figure out why this JavaScript won't work? It correctly generates the document.write output, but when you try to drag it it starts complaining about top and left not being set. any idea whats wrong?
abilitynames=new Array('Heal','Slash','Stab','Poison Slash','Knockout','','','','Tornado','','','','','','','','Icespike','','','','','','','','Bolt','Jumping Bolt','','','','','','','Roast','Burn','','','','','','','Earthquake','Rockwall','','','','','','','Kill','Deflect','Anti-Heal','','','','','','Backslash','Darkwall','Steal','Take','','','','');
abilitytypes=new Array(3,1,1,1,1,2,2,2,1,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,1,2,2,2,2,2,2,1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,2,1,2,3,2,2,2,2,2,1,2,3,3,2,2,2,2);
abilitycolors=new Array('#00FF00','#FFFFFF','#0000FF','#FFFF00','#FF0000','#AD6C00','#AD00FF','#000000');
for(i=0;i<64;i++){
document.write("<div onmousedown='dragging=this.id;this.style.position=\"fixed\";this.style.zIndex=1000;this.style.left=event.clientX-75;this.style.top=event.clientY-15;' onmouseout='if(dragging===this.id){this.style.left=event.clientX-75;this.style.top=event.clientY-15;}' onmousemove='if(dragging===this.id){this.style.left=event.clientX-75;this.style.top=event.clientY-15;}' onmouseup='dragging=false;if(event.clientX<450||event.clientY>"+(180+(abilitytypes[i]*90))+"||event.clientY<"+(100+((abilitytypes[i]-1)*(90*abilitytypes[i])/((4%abilitytypes[i])+1)))+"){this.style.position=\"relative\";this.style.top=0;this.style.left=0;this.style.zIndex=0;}else{this.style.left=460;this.style.top=(Math.round((event.clientY-30)/45)*45)+15;if(abilitys[Math.round((event.clientY-120)/45)]!=\"\"&&abilitys[Math.round((event.clientY-120)/45)]!=this.id){document.getElementById(abilitys[Math.round((event.clientY-120)/45)]).style.position=\"relative\";document.getElementById(abilitys[Math.round((event.clientY-120)/45)]).style.left=0;document.getElementById(abilitys[Math.round((event.clientY-120)/45)]).style.top=0;}abilitys[Math.round((event.clientY-120)/45)]=this.id;alert(abilitys);}' id='"+i+"' class='abilityblock"+abilitytypes[i]+"'><div class='abilityicon' style='background-position:"+(Math.floor(i/8)*-20)+"px "+((i%8)*-20)+"px;'></div><div class='abilityname' style='color:"+abilitycolors[Math.floor(i/8)]+";'>"+abilitynames[i]+"</div></div>");
}
I've probably broken the script just TRYING to clean up this unholy mess and simplifying things a little, but at least it seems to be a bit more readable now (not including the array definitions):
<script type="text/javascript">
var dragging;
function mouseDown(el) {
dragging = el.id;
el.style.position = "fixed";
el.style.zIndex = 1000;
el.style.left = event.clientX - 75;
el.style.top = event.clientY-15;
}
function mouseOut(el) {
if (dragging === el.id) {
el.style.left = event.clientX - 75;
el.style.top = event.clientY - 15;
}
}
function mouseMove(el) {
if (dragging === el.id) {
el.style.left = event.clientX - 75;
el.style.top = event.clientY - 15;
}
}
function mouseUp(el, i) {
dragging = false;
if ( (event.clientX < 450) ||
(event.clientY > (180 + (abilitytypes[i] * 90)) ) ||
(event.clientY < (100 + (abilitytypes[i] - 1) * (90 * abilitytypes[i]) / ((4 % abilitytypes[i]) + 1)))) {
el.style.position = "relative";
el.style.top = 0;
el.style.left = 0;
el.style.zIndex = 0;
} else {
el.style.left = 460;
el.style.top = (Math.round((event.clientY - 30) / 45) * 45) + 15;
if ((abilitys[Math.round((event.clientY - 120) / 45)] != "") && (abilitys[Math.round((event.clientY - 120) / 45)] != el.id)) {
var subel = document.getElementById(abilitys[Math.round((event.clientY-120)/45)]);
subel.style.position="relative";
subel.style.left=0;
subel.style.top=0;
}
abilitys[Math.round((event.clientY - 120) / 45)] = el.id;
alert(abilitys);
}
}
for(var i = 0; i < 64; i++){
document.write("
<div onmousedown='mouseDown(this);'
onmouseout='mouseOut(this);'
onmousemove='mouseMove(el);'
onmouseup='mouseUp(this, i);'
id='"+i+"'
class='abilityblock"+abilitytypes[i]+"'>
<div class='abilityicon' style='background-position:"+(Math.floor(i/8)*-20)+"px "+((i%8)*-20)+"px;'></div>
<div class='abilityname' style='color:"+abilitycolors[Math.floor(i/8)]+";'>"+abilitynames[i]+"</div>
</div>");
}
</script>
Phew. And after all that, I'm guessing your missing 'left' and 'top' parameters are because your dynamically computed element IDs are generating non-existent IDs in the mouseup handler.
My suggestion? Scrap this home-brew drag 'n drop stuff and use the functionality provided by Mootools or jQuery. Far less trouble, especially when having to deal with cross-browser differences.
Searching your code, you haven't defined an onmouseover event. You define onmousedown, onmouseout, onmousemove, and onmouseup. No onmouseover.
Related
Convert jQuery to JavaScript - mousemove
I am trying to convert this jQuery Code into Vanilla JavaScript code. I'm having trouble with some of the methods. I think I have some of them, but some of them not. Jquery: jQuery('.image').click(function() { jQuery(this).toggleClass('normal-zoom zoom-in'); }); jQuery('.image').on('mousemove', function(event) { var bbox = event.target.getBoundingClientRect(); var mouseX = event.clientX - bbox.left; var mouseY = event.clientY - bbox.top; var xPercent = (mouseX / bbox.width) * 100; var yPercent = (mouseY / bbox.height) * 100; jQuery(this).css('transform-origin', (xPercent+'% ' + yPercent+ '%') ); }); jQuery('.image').on('mouseenter', function() { jQuery(this).addClass('zoom-in'); jQuery(this).removeClass('normal-zoom'); }); jQuery('.image').on('mouseleave', function() { jQuery(this).addClass('normal-zoom'); jQuery(this).removeClass('zoom-in'); }); I tried. Javascript: document.querySelector('.image').onclick = function() { document.querySelector(this).classList.toggle('normal-zoom zoom-in'); }; document.querySelector('.image').addEventListener('mousemove', function(event) { var bbox = event.target.getBoundingClientRect(); var mouseX = event.clientX - bbox.left; var mouseY = event.clientY - bbox.top; var xPercent = (mouseX / bbox.width) * 100; var yPercent = (mouseY / bbox.height) * 100; document.querySelector(this).css('transform-origin', (xPercent+'% ' + yPercent+ '%') ); }); document.querySelector('.image').addEventListener('mouseenter', function() { document.querySelector(this).classList.add('zoom-in'); document.querySelector(this).classList.remove('normal-zoom'); }); document.querySelector('.image').addEventListener('mouseleave', function() { document.querySelector(this).classList.add('normal-zoom'); document.querySelector(this).classList.remove('zoom-in'); }); Where is the error?
I have added two comments to the code to show two lines I fixed and why they needed fixing. Additionally, I replaced every instance of document.querySelector(this) with document.querySelector('.image'), because the callbacks inside .onclick and .addEventListener do not bind this to the selected element the same way JQuery does, so you need to re-select the element each time. In your code, this is referencing the callback function, which is not what you want. document.querySelector('.image').onclick = function() { document.querySelector('.image').classList.toggle('zoom-in');// I split this line into two lines, because `.toggle()` can only accept one classname at a time. document.querySelector('.image').classList.toggle('normal-zoom'); }; document.querySelector('.image').addEventListener('mousemove', function(event) { var bbox = event.target.getBoundingClientRect(); var mouseX = event.clientX - bbox.left; var mouseY = event.clientY - bbox.top; var xPercent = (mouseX / bbox.width) * 100; var yPercent = (mouseY / bbox.height) * 100; document.querySelector('.image').style.transformOrigin = xPercent+'% ' + yPercent+'%';// There is no such `.css()` method on DOM nodes. Instead, set an element's css by using the `style` property. }); document.querySelector('.image').addEventListener('mouseenter', function() { document.querySelector('.image').classList.add('zoom-in'); document.querySelector('.image').classList.remove('normal-zoom'); }); document.querySelector('.image').addEventListener('mouseleave', function() { document.querySelector('.image').classList.add('normal-zoom'); document.querySelector('.image').classList.remove('zoom-in'); }); I would recommend using this code instead though, as it's cleaner, easier to read, implements DRY practices, and works to prevent bugs related to changes in the DOM. const imageElement = document.querySelector('.image'); imageElement.addEventListener('click', function() { imageElement.classList.toggle('zoom-in'); imageElement.classList.toggle('normal-zoom'); }; imageElement.addEventListener('mousemove', function(event) { const bbox = imageElement.getBoundingClientRect(); const mouseX = event.clientX - bbox.left; const mouseY = event.clientY - bbox.top; const xPercent = (mouseX / bbox.width) * 100; const yPercent = (mouseY / bbox.height) * 100; imageElement.style.transformOrigin = xPercent+'% ' + yPercent+'%'; }); imageElement.addEventListener('mouseenter', function() { imageElement.classList.add('zoom-in'); imageElement.classList.remove('normal-zoom'); }); imageElement.addEventListener('mouseleave', function() { imageElement.classList.add('normal-zoom'); imageElement.classList.remove('zoom-in'); });
Detect direction of touchpad swipe properly
I was able to scale in scale out x axis and y axis , Its working very good with arrow keys , I want to do that with touchpad aswel.I tried this below code ,its working but its not smooth .Sometimes when i zoom in X , its even zooming in Y and vice versa. window.addEventListener('mousewheel', function(e) { window.addEventListener('mousewheel', function(e) { e.preventDefault(); yDelta = e.deltaY; xDelta = e.deltaX; if (yDelta < -1 && Math.round(xDelta) < 1) { zoomOutY(); } else if (yDelta > 1 && Math.round(xDelta) < 1) { zoomInY(); } else if (xDelta < -1 && Math.round(yDelta) < 1) { zoomOut(); } else if (xDelta > -1 && Math.round(yDelta) < 1) { zoomIn(); } }, { passive: false }); And Again Same issue with mousemove method , how to detect the 4 directions smoothly , below is my code. document.addEventListener('mousemove', mouseMoveMethod); document.addEventListener('mousedown', mouseDownMethod); document.addEventListener('mouseup', mouseUpMethod); // Prevent context menu popup, so we can move our mouse. document.addEventListener('contextmenu', function(e) { e.preventDefault(); return false; }, false); mouseMoveMethod = function(e) { if (e.ctrlKey || mouseIsHeld) { let offsetX = 0 let offsetY = 0 if (e.pageX > oldx && e.pageY == oldy) { direction = "East"; offsetX -= 1 } else if (e.pageX == oldx && e.pageY > oldy) { direction = "South"; offsetY += 1 } else if (e.pageX == oldx && e.pageY < oldy) { direction = "North"; offsetY -= 1 } else if (e.pageX < oldx && e.pageY == oldy) { offsetX += 1 direction = "West"; } updateKeyboardPan(offsetX, offsetY); oldx = e.pageX; oldy = e.pageY; }) Again in the above code I am able to find the direction , but its lagging and hanging in middle.Is this the right approach ? or can I improve my code to improve my swipe/mousewheel direction , thank you.
I found a quite interesting example of multi-touch trackpad gestures in JavaScript. The code snippet below utilizes this for overriding LCJS chart interactions for trackpad. To me it seems to perform in a surprisingly intuitive manner for zooming in/out on pinch interaction (2 fingers, move to opposite directions) and panning with dragging 2 fingers in same direction. I did not find any way to differentiate pinch interaction along X and Y separately, it seems that the JS events just get a single value for both, which is assigned to deltaY. const { lightningChart } = lcjs; const { createProgressiveTraceGenerator } = xydata; const chart = lightningChart().ChartXY(); const series = chart.addLineSeries() createProgressiveTraceGenerator() .setNumberOfPoints(1000) .generate() .toPromise() .then(data => { series.add(data) }) chart.setMouseInteractionWheelZoom(false) chart.onSeriesBackgroundMouseWheel((_, e) => { const xInterval = chart.getDefaultAxisX().getInterval() const yInterval = chart.getDefaultAxisY().getInterval() if (e.ctrlKey) { // Zoom in / out (no separation of X or Y amount!) const zoomAmount = e.deltaY * 0.01 chart.getDefaultAxisX().setInterval(xInterval.start + zoomAmount * (xInterval.end - xInterval.start), xInterval.end - zoomAmount * (xInterval.end - xInterval.start), false, true) chart.getDefaultAxisY().setInterval(yInterval.start + zoomAmount * (yInterval.end - yInterval.start), yInterval.end - zoomAmount * (yInterval.end - yInterval.start), false, true) } else { // Pan X and Y simultaneously. const panX = e.deltaX * 0.001 * (xInterval.end - xInterval.start) const panY = e.deltaY * -0.001 * (yInterval.end - yInterval.start) chart.getDefaultAxisX().setInterval(xInterval.start + panX, xInterval.end + panX, false, true) chart.getDefaultAxisY().setInterval(yInterval.start + panY, yInterval.end + panY, false, true) } e.preventDefault() }) <script src="https://unpkg.com/#arction/xydata#1.4.0/dist/xydata.iife.js"></script> <script src="https://unpkg.com/#arction/lcjs#3.0.0/dist/lcjs.iife.js"></script>
clear javascript. dynamically created div resize: it only grow! why?
First off, the whole code is here, on pastebin. No jquery or alikes are employed! I have a HTML with a DIV created using document.createElement("div") and plugged into the page with document.getElementById('p').appendChild(d); The new DIV is provided with a bunch of event handlers: var d = document.createElement('div'); d.className = 'rect'; d.addEventListener('mousedown', catch_box, false); d.addEventListener('mouseup', release_box, false); d.addEventListener('mouseout', release_box, false); d.addEventListener('mousemove', mouse_move_box, false); d.addEventListener(wheel_hook, scroll_box, false); document.getElementById('p').appendChild(d); This works fine: // move the box around on 'mousemove' var lPos = cache.left + m_speed * cache.h_dir, tPos = cache.top + m_speed * cache.v_dir, ok = (lPos >= 0) && ((lPos + cache.width) <= max_width) && (tPos >= 0) && ((tPos + cache.height) <= max_height); if (ok) { box.style.left = lPos + 'px'; box.style.top = tPos + 'px'; } but this doesn't: // resize the box var hSize = cache.width + s_speed * cache.h_dir, vSize = cache.height + s_speed * cache.v_dir, ok = (hSize >= min_width) && ((cache.left + hSize) <= max_width) && (vSize >= min_height) && ((cache.top + vSize) <= max_height); if (ok) { box.setAttribute('style', 'width:'+hSize+'px;height:'+vSize+'px;'); box.style.width = hSize + 'px'; box.style.height = vSize + 'px'; } The box.style.width and box.style.height may only grow :( The question is: WHY?? And how to work it around?
JavaScript Css Animation
I have a Javascript animation at http://dev17.edreamz3.com/css/ All code works, however, there are performance problems. on Desktop, its good, On mobile things are so slow that it's unusable. I want to optimize the animation so that it runs smoothly on mobile. It can take 20 seconds or more for the animation to render. Right now the way the code is designed is in js/anim.js there is a render() function that gets executed every time a scroll event happens. The problem is that this routine is not efficient, that's what I think of. Each time render() executes it loops through all the paths and sections of the maze and redraws them, is there any alternative way or a strategy to get it working both on mobile as well as desktop. var offPathTime = 1000; window.offSection = -1; function render() { // var top = ($window.scrollTop() + (0.4 * $window.height())) / window.scale; var top = ($('.parent-div').scrollTop() + (0.4 * $('.parent-div').height())) / window.scale; top -= 660; top /= mazeSize.h; if (window.offSection != -1) { $body.addClass("blockScroll"); $('.parent-div').addClass("blockScroll"); // var wtop = $window.scrollTop() / window.scale; var wtop = $('.parent-div').scrollTop() / window.scale; wtop -= 660; wtop /= mazeSize.h; var $offSection = $("#offSection" + window.offSection); var $section = $("#section" + window.offSection); $(".section").removeClass("sectionActive"); $offSection.addClass("sectionActive"); $section.addClass("sectionActive"); var sTop = 200 -(mazeSize.h * (window.offSections[window.offSection].cy - wtop)); $container.animate({ left: 290 -(mazeSize.w * window.offSections[window.offSection].cx) + "px", top: sTop + "px" }, offPathTime); // Path var lr = offPaths[window.offSection].x1 > offPaths[window.offSection].x0; var dx = Math.abs(offPaths[window.offSection].x1 - offPaths[window.offSection].x0); var dashw = (dx * mazeSize.w) | 0; $offPaths[window.offSection].css("width", "0px"); $offPaths[window.offSection].show(); if (lr) { $offPaths[window.offSection].animate({ width: dashw + "px" }, offPathTime); } else { var x0 = offPaths[window.offSection].x0 * mazeSize.w; var x1 = offPaths[window.offSection].x1 * mazeSize.w; $offPaths[window.offSection].css("left", x0 + "px"); $offPaths[window.offSection].animate({ width: dashw + "px", left: x1 + "px" }, offPathTime); } return; } $body.removeClass("blockScroll"); $('.parent-div').removeClass("blockScroll"); $(".offPath").hide(); if ($container.css("top") != "0px") { $container.animate({ left: "-1550px", top: "0px" }, 500); } var pathIdx = -1; var path0 = paths[0]; var path1; var inPath = 0; var i; var curTop = 0; var found = false; for (i=0; i<paths.length; i++) { var top0 = (i == 0) ? 0 : paths[i-1].y; var top1 = paths[i].y; if (top >= top0 && top < top1) { pathIdx = i; path1 = paths[i]; inPath = (top - top0) / (top1 - top0); found = true; if (i > 0) { var dy = paths[i].y - paths[i-1].y; var dx = paths[i].x - paths[i-1].x; var vert = dx == 0; if (vert) $paths[i-1].css("height", (dy * mazeSize.h * inPath) + "px"); $paths[i-1].show(); } } else if (top >= top0) { path0 = paths[i]; var dy = paths[i].y - top0; var vert = dy != 0; if (i > 0) { if (vert) $paths[i-1].css("height", (dy * mazeSize.h) + "px"); $paths[i-1].show(); } } else { if (i > 0) { $paths[i-1].hide(); } } curTop = top1; } // Check for an active section $(".section").removeClass("sectionActive"); var section; for (i=0; i<sections.length; i++) { var d = Math.abs(sections[i].cy - (top - 0.05)); if (d < 0.07) { var $section = $("#section" + i); $section.addClass("sectionActive"); } } }
1) At the very least - assign all DOM objects to variables outside of the function scope. Like this: var $parentDiv = $('.parent-div'); var $sections = $(".section"); ... function render() { ... 2) Also you should probably stop animation before executing it again, like this: $container.stop(true).animate({ ... If you are running render() function on scroll - it will run many times per second. stop() helps to prevent it somewhat. 3) If it will not be sufficient - you can switch from jQuery to Zepto(jQuery-like api, but much faster and uses css transitions for animations) or to Velocity(basically drop-in replacement for jQuery $.animate and much faster than original) or even to GSAP - much more work obviously, but it is very fast and featured animation library.
Javascript and AJAX : Floating an image next to the cursor - questions
I have got a javascript code that will make a floating image appear next to the mouse pointer (and through the use of php it shows the image that the mosue is hovering over, but full size because the image on the page itself is sized down a bit). But whilst it is OK if the image is on the left of the page, there is a problem if the image is on the right hand side. The code: <script> var cX = 0; var cY = 0; var rX = 0; var rY = 0; function UpdateCursorPosition(e){ cX = e.pageX; cY = e.pageY;} function UpdateCursorPositionDocAll(e){ cX = event.clientX; cY = event.clientY;} if(document.all) { document.onmousemove = UpdateCursorPositionDocAll; } else { document.onmousemove = UpdateCursorPosition; } function AssignPosition(d) { if(self.pageYOffset) { rX = self.pageXOffset; rY = self.pageYOffset; } else if(document.documentElement && document.documentElement.scrollTop) { rX = document.documentElement.scrollLeft; rY = document.documentElement.scrollTop; } else if(document.body) { rX = document.body.scrollLeft; rY = document.body.scrollTop; } if(document.all) { cX += rX; cY += rY; } d.style.left = (cX+10) + "px"; d.style.top = (cY+10) + "px"; } function HideContent(d) { if(d.length < 1) { return; } document.getElementById(d).style.display = "none"; } function ShowContent(d,i) { if(d.length < 1) { return; } var dd = document.getElementById(d); AssignPosition(dd); dd.style.display = "block"; $(d).setHTML ('<img src="'+i'" />'); } function ReverseContentDisplay(d) { if(d.length < 1) { return; } var dd = document.getElementById(d); AssignPosition(dd); if(dd.style.display == "none") { dd.style.display = "block"; } else { dd.style.display = "none"; } } //--> </script> Here is a standard image that will trigger the floating content: <a onmousemove="ShowContent('FloatingImage','image.jpg'); return true;" onmouseover="ShowContent('FloatingImage','image.jpg'); return true;" onmouseout="HideContent('FloatingImage','image.jpg'); return true;" href="javascript:ShowContent('FloatingImage','image.jpg')">standard html</a> <div id="FloatingImage" style="display:none; position:absolute; border-style: solid; background-color: white; padding: 5px; z-index:+1"> <img id="MouseImage" name="MouseImage" src="LR-10.jpg" /> </div> --end code-- .... On its own this is fine and it works. as you can float the mouse over the next thumbnail image and the floating image changes accordingly whilst keeping aspect ratio. BUT if the thumbnail image is on the right hand side, the floating image is off the right hand edge of the screen and cannot be seen: is there any way of placing a 'block' within the JS code so that if the thumbnail image is close to the edge of the content (screen edge or edge of the containing DV layer) than it shows the image on the left hand side of the mouse pointer instead? Next question: this code works fine if I open the page on its own - BUT my website design will be calling the page to open inside a DIV layer by means of AJAX. This breaks the code and it doesn't work then. This has happened with other scripts I have written: works fine by itself, but put in through an AJAX load request and it fails. How can this be solved? Thanks.
I've modified your script so that the image will switch to the left when the mouse is too far to the right: var cX = 0, cY = 0, rX = 0, rY = 0, vW; function UpdateCursorPosition(e) { cX = e.pageX; cY = e.pageY; } function UpdateCursorPositionDocAll(e) { cX = event.clientX; cY = event.clientY; } if (document.all) { document.onmousemove = UpdateCursorPositionDocAll; } else { document.onmousemove = UpdateCursorPosition; } function AssignPosition(d) { if (self.pageYOffset) { rX = self.pageXOffset; rY = self.pageYOffset; } else if (document.documentElement && document.documentElement.scrollTop) { rX = document.documentElement.scrollLeft; rY = document.documentElement.scrollTop; } else if (document.body) { rX = document.body.scrollLeft; rY = document.body.scrollTop; } if (document.all) { cX += rX; cY += rY; } var oW = d.offsetWidth; if (cX + 10 + oW > vW) d.style.left = (cX - 10 - oW) + 'px'; else d.style.left = (cX+10) + 'px'; d.style.top = (cY+10) + 'px'; } function HideContent(d) { if (d.length < 1) return; document.getElementById(d).style.display = 'none'; } function ShowContent(d,i) { vW = ViewportWidth(); if (d.length < 1) return; var dd = document.getElementById(d); AssignPosition(dd); dd.style.display = 'block'; document.getElementById(d).innerHTML = '<img src="'+i+'" />'; } function ReverseContentDisplay(d) { if (d.length < 1) return; var dd = document.getElementById(d); AssignPosition(dd); dd.style.display = (dd.style.display=='none')? 'block' : 'none'; } function ViewportWidth() { if (self.innerWidth) return self.innerWidth; else if (document.documentElement && document.documentElement.clientWidth) return document.documentElement.clientWidth; else if (document.body) return document.body.clientWidth; }