I am struggleing in issue. The issue that i am trying to popup context menu but when i click at the edges of the container div. the context menu getting flow out from this container div.
Example :
This is the menu when i click somewhere away from the edges.
This what happen if i click near to the edges.
HTML:-
<div id="rows-menu-wrapper-container" class="rows-menu-wrapper-container" style="/*display: none;*/" onclick="$(this).remove()">
<div id="rows-menu-wrapper" class="rows-menu-wrapper">
<div id="rows-menu-wrapper-menu-item" class="rows-menu-wrapper-menu-item"><label class="form-label text-truncate rows-menu-wrapper-menu-item-label">Open Menu</label></div>
</div>
</div>
CSS:-
.rows-menu-wrapper-container {
width: 100vw;
height: 100vh;
position: fixed;
top: 0px;
left: 0px;
pointer-events: auto;
background-color: rgba(26,26,26,0.11);
}
Placing the menu using JS:-
// top position
var topY = e.target.getBoundingClientRect().top + document.documentElement.scrollTop
var topX = e.target.getBoundingClientRect().left + document.documentElement.scrollLeft - 250
newPaper.find(".rows-menu-wrapper").css('top' , topY + 'px' )
newPaper.find(".rows-menu-wrapper").css('left' , topX + 'px' )
$('body').append(newPaper)
var paperHeight = newPaper.css('height').replace('px' , '') - 400
var delta = (e.clientY - newPaper.css('height').replace('px' , ''))
delta = parseFloat(delta.toString().replace('-' , '') )
delta = delta * 1.5
if ( paperHeight <= e.clientY ){newPaper.find(".rows-menu-wrapper").css('top' , topY - delta + 'px' )}
I Checked many guides but never understand how it is work.
I would be greatful if someone make it simple for me :(
UPDATE1
I managet to get around of this with below:
// top position
var topY = e.target.getBoundingClientRect().top + document.documentElement.scrollTop
var topX = e.target.getBoundingClientRect().left + document.documentElement.scrollLeft - 250
newPaper.find(".rows-menu-wrapper").css('left' , topX + 'px' )
newPaper.find(".rows-menu-wrapper").css('top' , topY + 'px' )
$('body').append(newPaper)
var totalHeight = newPaper.css('height').replace('px' , '')
var clickY = e.clientY
var elementHight = newPaper.find(".rows-menu-wrapper").css('height').replace('px' , '')
var delta = totalHeight - clickY - elementHight
if (delta <= 0){topY = topY - elementHight + 20 }
newPaper.find(".rows-menu-wrapper").css('top' , topY + 'px' )
IDK if this approach is ok or not clean.
I am JavaScript Beginner and I am working on a small code where I have an image displayed inside a Modal and I am trying to draw a bounding box over the image.
I have tried the following code to draw the bounding box over the image.
Html: ( the code for the modal that shows the image)
<div id="myModal" class="modal">
<!-- The Close Button -->
<span class="close">×</span>
<!-- Modal Content (The Image) -->
<div id="imagearea" class="imagearea">
<img class="modal-content" id="img01">
</div>
</div>
Javascript: ( the logic that I tried to draw a bounding box over the image)
initDraw(document.getElementById('imgarea'));
function initDraw(imgarea) {
var mouse = {
x: 0,
y: 0,
startX: 0,
startY: 0
};
function setMousePosition(e) {
var ev = e || window.event; //Moz || IE
if (ev.pageX) { //Moz
mouse.x = ev.pageX + window.pageXOffset;
mouse.y = ev.pageY + window.pageYOffset;
} else if (ev.clientX) { //IE
mouse.x = ev.clientX + document.body.scrollLeft;
mouse.y = ev.clientY + document.body.scrollTop;
}
};
var element = null;
imgarea.onmousemove = function (e) {
setMousePosition(e);
if (element !== null) {
element.style.width = Math.abs(mouse.x - mouse.startX) + 'px';
element.style.height = Math.abs(mouse.y - mouse.startY) + 'px';
element.style.left = (mouse.x - mouse.startX < 0) ? mouse.x + 'px' : mouse.startX + 'px';
element.style.top = (mouse.y - mouse.startY < 0) ? mouse.y + 'px' : mouse.startY + 'px';
}
}
imagearea.onmouseup = function (e) {
if (element !== null) {
element = null;
imagearea.style.cursor = "default";
console.log("finsihed.");
} }
imagearea.onmousedown = function (e) {
if(element==null){
console.log("begun.");
mouse.startX = mouse.x;
mouse.startY = mouse.y;
element = document.createElement('div');
element.className = 'rectangle'
element.style.left = mouse.x + 'px';
element.style.top = mouse.y + 'px';
imagearea.appendChild(element)
imagearea.style.cursor = "crosshair";
e.preventDefault();
}
}
}
css: (for the bounding box)
.rectangle {
border: 10px solid red;
position: absolute;
}
.imagearea {
display: flex;
flex-direction: column;
float: left;
width: 35%;
max-width: 700px;
position: relative;
}
#img01{
position: absolute;
}
The above code displays the image in modal and when I try to draw the bounding box on the image, the cursor changes to crosshair as expected , but I could not see the bounding box when i draw it over the image. Just the cursor changes but the rectangle(bounding box) which I draw over the image is not visible.
Can some one help me with this. Thank you
There are two problems.
You can't append children to <img>.
Your calculations are based on the viewport, while border's CSS is relative to the image. There are multiple ways to fix that, the quickest one would be to subtract image's position from your mouse position, like this:
function setMousePosition(e) {
// your mouse calculations
const boundaries = e.currentTarget.getBoundingClientRect();
mouse.x -= boundaries.left;
mouse.y -= boundaries.top;
}
Also, make sure you use setMousePosition() in your mousedown handler.
This is my first question, so please give me any pointers on how I could ask better ones.
Anyway, how would I make a togglable menu that displays links, that activates using a bookmarklet. I have tried to find answers, but all were fruitless. Would I need to create a new element for this?
You will need to create the pop-up menu using vanilla JS. I also implemented drag functionality. The only thing this needs is to correctly set the position when a page is scrolled.
DOM layout
The most important elements and styles below are required.
<div style="position:absolute; z-index:2147483647">
<div style="position: relative">
<div style="position:relative; display:inline-block; left:0">Bookmarklet Links</div>
<div style="position:relative; float:right">×</div>
</div>
<div>
<p>Click the links to open a new tab!</p>
<ul>
<li>
Google
</li>
<li>
Bing
</li>
<li>
DuckDuckGO
</li>
</ul>
</div>
</div>
You can save the following bookmarklet:
javascript:!function(){var c=0x1f4,d=0x12c,e='#AAA',f=0x1,g=0x20,h='#444',i='#FFF',j='Bookmarklet\x20Links',k=~~(document['documentElement']['clientWidth']/0x2-c/0x2),l=~~(document['documentElement']['clientHeight']/0x2-d/0x2),m=~~(0.8*g),n=document['createElement']('DIV');Object['assign'](n['style'],{'position':'absolute','left':k+'px','top':l+'px','zIndex':Number['MAX_SAFE_INTEGER'],'width':c+'px','height':d+'px','background':e,'border':f+'px\x20solid\x20black'});var o=document['createElement']('DIV');Object['assign'](o['style'],{'position':'relative','width':c+'px','height':g+'px','background':h,'borderBottom':f+'px\x20solid\x20black'});var p=document['createElement']('DIV');Object['assign'](p['style'],{'position':'relative','display':'inline-block','left':0x0,'width':~~(c-0x2*m)+'px','lineHeight':g+'px','color':i,'fontSize':~~(0.667*g)+'px','marginLeft':~~(m/0x3)+'px'}),p['textContent']=j;var q=document['createElement']('DIV'),r=~~((g-m)/0x2);Object['assign'](q['style'],{'position':'relative','float':'right','right':r+'px','top':r+'px','width':m+'px','height':m+'px','background':'#F00','border':f+'px\x20solid\x20black','color':'#FFF','lineHeight':m+'px','textAlign':'center','fontSize':m+'px','marginLeft':'auto','marginRight':0x0});var s=document['createElement']('DIV');Object['assign'](s['style'],{'padding':'1em'});var t=document['createElement']('P');t['textContent']='Click\x20the\x20links\x20to\x20open\x20a\x20new\x20tab!',s['appendChild'](t);var u=document['createElement']('UL');[{'name':'Google','url':'https://www.google.com'},{'name':'Bing','url':'https://www.bing.com'},{'name':'DuckDuckGO','url':'https://duckduckgo.com'}]['forEach'](c=>{var d=document['createElement']('LI'),e=document['createElement']('A');e['setAttribute']('href',c['url']),e['setAttribute']('target','_blank'),e['textContent']=c['name'],d['appendChild'](e),u['appendChild'](d);}),s['appendChild'](u),q['addEventListener']('click',function c(d){q['removeEventListener']('click',c,!0x1);o['removeChild'](q);n['removeChild'](o);n['removeChild'](s);document['body']['removeChild'](n);},!0x1),q['textContent']='×',o['appendChild'](p),o['appendChild'](q),n['appendChild'](o),n['appendChild'](s),document['body']['appendChild'](n),function(c){var d=function(c){var d=c['getBoundingClientRect'](),e=window['pageXOffset']||document['documentElement']['scrollLeft'],f=window['pageYOffset']||document['documentElement']['scrollTop'];return{'top':d['top']+f,'left':d['left']+e};}(c['parentElement']),e=!0x1,f={'x':0x0,'y':0x0},g={'x':d['left'],'y':d['top']};c['parentElement']['addEventListener']('mousedown',function(d){e=!0x0,f['x']=d['clientX'],f['y']=d['clientY'],c['parentElement']['style']['cursor']='move';}),c['parentElement']['addEventListener']('mouseup',function(d){e=!0x1,g['x']=parseInt(c['parentElement']['style']['left'])||0x0,g['y']=parseInt(c['parentElement']['style']['top'])||0x0,c['parentElement']['style']['cursor']='auto';}),document['addEventListener']('mousemove',function(d){if(!e)return;var h={'x':d['clientX']-f['x'],'y':d['clientY']-f['y']},i={'x':g['x']+h['x'],'y':g['y']+h['y']};i['x']<0x0?i['x']=0x0:i['x']+c['parentElement']['offsetWidth']>document['documentElement']['clientWidth']&&(i['x']=document['documentElement']['clientWidth']-c['parentElement']['offsetWidth']);i['y']<0x0?i['y']=0x0:i['y']+c['parentElement']['offsetHeight']>document['documentElement']['clientHeight']&&(i['y']=document['documentElement']['clientHeight']-c['parentElement']['offsetHeight']);c['parentElement']['style']['left']=i['x']+'px',c['parentElement']['style']['top']=i['y']+'px';});}(o);}(window);
Method of minification and obfuscation
I minified the code below using: https://javascript-minifier.com/
I obfuscated the resulting minified code using: https://obfuscator.io/
For the obfuscator, I set "Identifier Names Generator" to "mangled" and checked "Rename Globals".
Important: Unselect "String Array" or you cannot add new link entries.
Caveats
The script doesn't allow moving beyond the initial width and height. The following width and height methods from this post could be incorporated to fix this limitation.
Source code
(function(window) {
var links = [{
name: 'Google',
url: 'https://www.google.com'
}, {
name: 'Bing',
url: 'https://www.bing.com'
}, {
name: 'DuckDuckGO',
url: 'https://duckduckgo.com'
}];
var props = {
width: 500,
height: 300,
background: '#AAA',
borderThickness: 1,
headerHeight: 32,
headerBackground: '#444',
headerTitleColor: '#FFF',
windowTitle: 'Bookmarklet Links'
};
var windowPosition = {
left: ~~((document.documentElement.clientWidth / 2) - (props.width / 2)),
top: ~~((document.documentElement.clientHeight / 2) - (props.height / 2)),
}
var btnSize = ~~(props.headerHeight * 0.8);
var popupEl = document.createElement('DIV');
Object.assign(popupEl.style, {
position: 'absolute',
left: windowPosition.left + 'px',
top: windowPosition.top + 'px',
zIndex: Number.MAX_SAFE_INTEGER,
width: props.width + 'px',
height: props.height + 'px',
background: props.background,
border: props.borderThickness + 'px solid black'
});
var popupHeader = document.createElement('DIV');
Object.assign(popupHeader.style, {
position: 'relative',
width: (props.width) + 'px',
height: props.headerHeight + 'px',
background: props.headerBackground,
borderBottom: props.borderThickness + 'px solid black'
});
var popupHeaderTitle = document.createElement('DIV');
Object.assign(popupHeaderTitle.style, {
position: 'relative',
display: 'inline-block',
left: 0,
width: ~~(props.width - btnSize * 2) + 'px',
lineHeight: props.headerHeight + 'px',
color: props.headerTitleColor,
fontSize: ~~(props.headerHeight * 0.667) + 'px',
marginLeft: ~~(btnSize / 3) + 'px'
});
popupHeaderTitle.textContent = props.windowTitle;
var closeButton = document.createElement('DIV');
var margin = ~~((props.headerHeight - btnSize) / 2);
Object.assign(closeButton.style, {
position: 'relative',
float: 'right',
right: margin + 'px',
top: margin + 'px',
width: btnSize + 'px',
height: btnSize + 'px',
background: '#F00',
border: props.borderThickness + 'px solid black',
color: '#FFF',
lineHeight: btnSize + 'px',
textAlign: 'center',
fontSize: btnSize + 'px',
marginLeft: 'auto',
marginRight: 0
});
var popupBody = document.createElement('DIV');
Object.assign(popupBody.style, {
padding: '1em'
});
var p = document.createElement('P');
p.textContent = 'Click the links to open a new tab!';
popupBody.appendChild(p);
var listEl = document.createElement('UL');
links.forEach(link => {
var itemEl = document.createElement('LI');
var anchorEl = document.createElement('A');
anchorEl.setAttribute('href', link.url);
anchorEl.setAttribute('target', '_blank');
anchorEl.textContent = link.name;
itemEl.appendChild(anchorEl);
listEl.appendChild(itemEl);
});
popupBody.appendChild(listEl);
closeButton.addEventListener('click', destroyWindow, false);
closeButton.textContent = '×';
popupHeader.appendChild(popupHeaderTitle);
popupHeader.appendChild(closeButton);
popupEl.appendChild(popupHeader);
popupEl.appendChild(popupBody);
document.body.appendChild(popupEl);
draggable(popupHeader);
function destroyWindow(e) {
closeButton.removeEventListener('click', destroyWindow, false);
popupHeader.removeChild(closeButton);
popupEl.removeChild(popupHeader);
popupEl.removeChild(popupBody);
document.body.removeChild(popupEl);
}
/* Source: https://plainjs.com/javascript/styles/get-the-position-of-an-element-relative-to-the-document-24/ */
function offset(el) {
var rect = el.getBoundingClientRect(),
scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
scrollTop = window.pageYOffset || document.documentElement.scrollTop;
return { top: rect.top + scrollTop, left: rect.left + scrollLeft }
}
/* Source: https://gist.github.com/remarkablemark/5002d27442600510d454a5aeba370579 */
function draggable(el) {
var initialOffset = offset(el.parentElement);
var isMouseDown = false;
var currPos = { x : 0, y : 0 };
var elPos = { x : initialOffset.left, y : initialOffset.top };
el.parentElement.addEventListener('mousedown', onMouseDown);
function onMouseDown(event) {
isMouseDown = true;
currPos.x = event.clientX;
currPos.y = event.clientY;
el.parentElement.style.cursor = 'move';
}
el.parentElement.addEventListener('mouseup', onMouseUp);
function onMouseUp(event) {
isMouseDown = false;
elPos.x = parseInt(el.parentElement.style.left) || 0;
elPos.y = parseInt(el.parentElement.style.top) || 0;
el.parentElement.style.cursor = 'auto';
}
document.addEventListener('mousemove', onMouseMove);
function onMouseMove(event) {
if (!isMouseDown) return;
var delta = { x : event.clientX - currPos.x, y: event.clientY - currPos.y };
var pos = { x : elPos.x + delta.x, y : elPos.y + delta.y };
if (pos.x < 0) {
pos.x = 0;
} else if (pos.x + el.parentElement.offsetWidth > document.documentElement.clientWidth) {
pos.x = document.documentElement.clientWidth - el.parentElement.offsetWidth;
}
if (pos.y < 0) {
pos.y = 0;
} else if (pos.y + el.parentElement.offsetHeight > document.documentElement.clientHeight) {
pos.y = document.documentElement.clientHeight - el.parentElement.offsetHeight;
}
el.parentElement.style.left = pos.x + 'px';
el.parentElement.style.top = pos.y + 'px';
}
}
})(window);
Improving
You will notice that if your cursor goes off-screen while dragging (and you release the button) the window will be stuck in drag. You could detect this globally, but you will also need to figure out how re reinitialize the position to last known "good" position.
document.addEventListener('mouseup', onGlobalMouseUp);
function onGlobalMouseUp(event) {
if (
(event.clientX < 0 || event.clientX > document.documentElement.clientWidth) ||
(event.clientY < 0 || event.clientY > document.documentElement.clientHeight)
) {
if (isMouseDown) {
isMouseDown = false; // Draggged off-screen
popupEl.style.cursor = 'auto';
}
}
}
Lastly, don't spam the bookmarklet button, because it will create multiple instances of the same window. Code can be added to detect the presence of the window before creating a new one. Closing it could hide it, so it will just make the existing one visible again. Multiple windows will break the close listener.
I have a selection on a canvas, that I can drag and resize when it´s there.
I also can make it visible when I drag on the empty canvas.
But how do I make it visible and instantly have the bottom-right corner "in my hand" (for resizing); i.e. can I pass the drag event from the canvas to a resize event on the selection?
Is there a way with jQuery or do I have to make my own?
<div id="canvas" style="position:relative;width:500px;height:500px"
draggable="true" onDragStart="initSelection(event)">
<div id="selection" style="border:1px dashed gray;position:absolute;display:none"></div>
</div>
$('#selection').draggable({containment:'parent'}).resizable({containment:'parent'});
function initSelection(e){
if ('none'==$('#selection').css('display'))
{
var q=$('#canvas').offset();
$('#selection')
.css('left', e.clientX-q.left)
.css('top', e.clientY-q.top)
.css('width',10).css('height',10)
.css('display','block')
;
}
}
I think I see what you're trying to do.
Testing here: jsfiddle.net/Twisty/vkLjn0gL
I think you need to take one route or the other, not both at once.
resize the div with CSS based on the mousedown / mouseup events and
mouse x and y.
make it resizable up front and enable/start the resize
event tied to the mousemove until done and then make it draggable
I got this far when you posted that you found an answer: https://jsfiddle.net/Twisty/vkLjn0gL/5/
$(function() {
$("#canvas").on("dragstart", initSelection);
$("#canvas").on("mousemove", resize);
$("#canvas").on("mouseup", function() {
allowResize = false;
});
var allowResize = false;
/*
$('#selection').draggable({
containment: 'parent'
}).resizable({
containment: 'parent'
});
*/
function initSelection(e) {
if ('none' == $('#selection').css('display')) {
var q = $('#canvas').offset();
$('#selection')
.css('left', e.clientX - q.left)
.css('top', e.clientY - q.top)
.css('width', '10px').css('height', '10px')
.css('display', 'block');
allowResize = true;
}
}
function resize(e) {
if (allowResize) {
//console.log("MouseMove: ", e);
var w = $("#selection").width(),
h = $("#selection").height(),
q = $("#canvas").offset(),
px = 0,
py = 0;
px = e.clientX - q.left;
py = e.clientY - q.top;
console.log("Width: ", (w + px), " Height: ", (h + py));
$("#selection").css({
width: (w + px) + "px",
height: (h + py) + "px"
});
}
}
});
Update 1
Few fixes to mouse tracking:
https://jsfiddle.net/Twisty/vkLjn0gL/6/
function resize(e) {
if (allowResize) {
//console.log("MouseMove: ", e);
$("#canRes").html(allowResize);
$("#cx").html(e.clientX - $("#canvas").offset().left);
$("#cy").html(e.clientY - $("#canvas").offset().top);
$("#ox").html($("#selection").width());
$("#oy").html($("#selection").height());
var w = $("#selection").width(),
h = $("#selection").height(),
q = $("#canvas").offset(),
o = $("#selection").position();
px = 0,
py = 0;
if (w > $("#canvas").width() + q.left) {
return false;
}
if (h > $("#canvas").height() + q.top) {
return false;
}
px = e.clientX - q.left - o.left;
py = e.clientY - q.top - o.top;
$("#selection").css({
width: px + "px",
height: py + "px"
});
}
}
Update 2
I think this will do all that you wanted if you're still looking: https://jsfiddle.net/Twisty/vkLjn0gL/7/
Updated to selection after mouseup
$("#canvas").on("mouseup", function() {
allowResize = false;
$("#canRes").html(allowResize);
$("#selection").draggable({
containment: 'parent'
})
.resizable({
containment: 'parent'
});
});
Update 3
Added the drag handle on initial sizing: https://jsfiddle.net/Twisty/vkLjn0gL/10/
I built a magnifying glass in JavaScript, which works well when I click on it or click and dragging it, but it should not hide from the screen.
$(".menu-left-preview-box-preview").bind('click', function (e) {
window.location = "page" + ($(this).index() + 1) + ".html";
});
var native_width = 0;
var native_height = 0;
var magnifyIsMouseDown = false;
$(".magnify").parent().mousedown(function (e) {
magnifyIsMouseDown = true;
});
$(".magnify").mousemove(function (e) {
if (magnifyIsMouseDown) {
if (!native_width && !native_height) {
var image_object = new Image();
image_object.src = $(".small").attr("src");
native_width = image_object.width;
native_height = image_object.height;
} else {
var magnify_offset = $(this).offset();
var mx = e.pageX - magnify_offset.left;
var my = e.pageY - magnify_offset.top;
if (mx < $(this).width() && my < $(this).height() && mx > 0 && my > 0) {
$(".large").fadeIn(100);
} else {
$(".large").fadeOut(100);
}
if ($(".large").is(":visible")) {
var rx = Math.round(mx / $(".small").width() * native_width - $(".large").width() / 2) * -1;
var ry = Math.round(my / $(".small").height() * native_height - $(".large").height() / 2) * -1;
var bgp = rx + "px " + ry + "px";
var px = mx - $(".large").width() / 2;
var py = my - $(".large").height() / 2;
$(".large").css({ left: px, top: py, backgroundPosition: bgp });
}
}
}
});
$(".magnify").parent().mouseup(function (e) {
magnifyIsMouseDown = false;
$(".large").fadeOut(100);
});
$(".magnify").parent().mouseleave(function (e) {
$(".large").fadeOut(100);
});
manageSlide();
By default the magnifying glass must be there on the screen. The magnifying glass can be dragged and after it's dropped it must remain there at it's dropped position.
On clicking and dragging the magnify glass is working well, but it should not hide from the screen. It should be there on screen.
Provide handle of magnify glass with that circle (in design).
Working example: http://jsfiddle.net/mohsin80/4ww8efx5/
I replaced the if (magnifyIsMouseDown) { by if (isDragging) { and created the following methods:
var isDragging = false;
$(".magnify").parent().mouseup(function(e) {
isDragging = false;
});
$(".magnify").parent().mousedown(function(e) {
isDragging = true;
});
To make a simulated drag event with jQuery.
Here is the fiddle. Hope it helped :)