I am using Angular Material Bottom Sheet, but I want it in such a way, that it should get adjusted, when the user drags it up and down from the bottom.
I have used one plugin to resize the bottom sheet, but the bottom sheet is getting dragged up and down without resizing, it's bottom is not fixed.
Here's the working code in plunkar.
resizer.js:
angular.module('mc.resizer', []).directive('resizer', function($document) {
return function($scope, $element, $attrs) {
$element.on('mousedown', function(event) {
event.preventDefault();
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
});
function mousemove(event) {
if ($attrs.resizer == 'vertical') {
// Handle vertical resizer
var x = event.pageX;
if ($attrs.resizerMax && x > $attrs.resizerMax) {
x = parseInt($attrs.resizerMax);
}
$element.css({
left: x + 'px'
});
$($attrs.resizerLeft).css({
width: x + 'px'
});
$($attrs.resizerRight).css({
left: (x + parseInt($attrs.resizerWidth)) + 'px'
});
} else {
// Handle horizontal resizer
var y = window.innerHeight - event.pageY;
if((window.innerHeight-100 > y)&&(y>100)){
$element.css({
bottom: y + 'px'
});
$($attrs.resizerTop).css({
bottom: (y + parseInt($attrs.resizerHeight)) + 'px'
});
$($attrs.resizerBottom).css({
height: y + 'px'
});
}
}
}
function mouseup() {
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
}
};
});
Related
I have created a menu that it is bigger than the width of the page.
And I want when it goes to it's last item, the first will appear again like a circle with no end.
here is the css code of the menu
`.slider
width: 200%
height: 65vh
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
display: flex
align-items: center
user-select: none
transition: all 0s
&:hover
cursor: grab`
and this is the js
var isDown = false;
var startX;
var mousePosition;
var offset = [0,0];
$('.slider').mousedown(function(e) {
$(this).css('cursor', 'grabbing');
$('.pointer').css({'width': '55px', 'height': '55px'});
isDown = true;
startX = e.clientX;
offset = [
this.offsetLeft - e.clientX,
this.offsetTop - e.clientY
];
// var startX = e.pageX;
// var math = Math.round(Math.sqrt(Math.pow(startX - event.clientX, 2))) + 'px';
// $(this).css('transform', 'translate(' + math + 'px, -50%)');
// console.log(math);
});
$('.slider').mousemove(function(e) {
// e.preventDefault();
if (isDown){
// var tap = $('.slider').offset().left;
// console.log(e.pageX - tap);
mousePosition = e.clientX ;
console.log(mousePosition);
// $(this).css('transform', 'translate(' + mousePosition + ', -50%)');
// console.log(e);
this.style.left = (mousePosition + offset[0]) + 'px';
startX = mousePosition;
// this.style.transform = "translate3d(" + 0 + "1110px, " + 0 + "0px, 0)";
// div.style.left = (mousePosition.x + offset[0]) + 'px';
}
});
$('.slider').mouseup(function() {
$(this).css('cursor', 'grab');
$('.pointer').css({'width': '30px', 'height': '30px'});
isDown = false;
});
When the slider goes to it's last item it ends, but I want the first one to appear again.
May I suggest using an already existing library?
There is a library called Endless.js, and this does exactly what you asked for. The demo can be found here.
I have this script, and it does exactly what I want. shows and hides a div and follows mouse-cursor around and does it only when viewport is a certain size and above, but I would like to know how to condense it so the whole script is not duplicated twice, one for on load and one for when listening to browser window resizing.
<script>
$( document ).ready(function() { //document ready
$( window ).on( "load", function() { //entire page has loaded
if ($(window).width() < 963) {
tip = $(this).nextAll('#tail');
tip.hide();
}
else {
//Tooltips
$("#mainbody").hover(function(){
tip = $(this).nextAll('#tail');
tip.show(); //Show tooltip
}, function() {
tip.hide(); //Hide tooltip
}).mousemove(function(e) {
if ($(window).width() > 962) {
//Change these numbers to move the tooltip offset
var mousex = e.pageX + 20; //Get X coodrinates
var mousey = e.pageY + 20; //Get Y coordinates
var tipWidth = tip.width(); //Find width of tooltip
var tipHeight = tip.height(); //Find height of tooltip
//Distance of element from the right edge of viewport
var tipVisX = $(window).width() - (mousex + tipWidth);
//Distance of element from the bottom of viewport
//var tipVisY = $(window).height() - (mousey + tipHeight);
var tipVisY = $("#mainbody").height() - (tipHeight);
if (tipVisX < 1) { //If tooltip exceeds the X coordinate of viewport
//mousex = e.pageX - tipWidth - 20;
} if (tipVisY < 1) { //If tooltip exceeds the Y coordinate of viewport
//mousey = e.pageY - tipHeight - 20;
}
//Absolute position the tooltip according to mouse position
tip.css({ top: mousey, left: mousex });
}
});
}
$( window ).resize(function() {
if ($(window).width() < 963) {
tip = $(this).nextAll('#tail');
tip.hide();
}
else {
//Tooltips
$("#mainbody").hover(function(){
tip = $(this).nextAll('#tail');
tip.show(); //Show tooltip
}, function() {
tip.hide(); //Hide tooltip
}).mousemove(function(e) {
if ($(window).width() > 962) {
//Change these numbers to move the tooltip offset
var mousex = e.pageX + 20; //Get X coodrinates
var mousey = e.pageY + 20; //Get Y coordinates
var tipWidth = tip.width(); //Find width of tooltip
var tipHeight = tip.height(); //Find height of tooltip
//Distance of element from the right edge of viewport
var tipVisX = $(window).width() - (mousex + tipWidth);
//Distance of element from the bottom of viewport
//var tipVisY = $(window).height() - (mousey + tipHeight);
var tipVisY = $("#mainbody").height() - (tipHeight);
if (tipVisX < 1) { //If tooltip exceeds the X coordinate of viewport
//mousex = e.pageX - tipWidth - 20;
} if (tipVisY < 1) { //If tooltip exceeds the Y coordinate of viewport
//mousey = e.pageY - tipHeight - 20;
}
//Absolute position the tooltip according to mouse position
tip.css({ top: mousey, left: mousex });
}
});
}
});
});
});
</script>
You can insert code to function and call this function where you want.
$( document ).ready(function() { //document ready
$( window ).on( "load", function() { //entire page has loaded
change(this)
$( window ).resize(function() {
change(this)
});
});
});
function change(_this){
if ($(window).width() < 963) {
tip = $(_this).nextAll('#tail');
tip.hide();
}
else {
//Tooltips
$("#mainbody").hover(function(){
tip = $(this).nextAll('#tail');
tip.show(); //Show tooltip
}, function() {
tip.hide(); //Hide tooltip
}).mousemove(function(e) {
if ($(window).width() > 962) {
//Change these numbers to move the tooltip offset
var mousex = e.pageX + 20; //Get X coodrinates
var mousey = e.pageY + 20; //Get Y coordinates
var tipWidth = tip.width(); //Find width of tooltip
var tipHeight = tip.height(); //Find height of tooltip
//Distance of element from the right edge of viewport
var tipVisX = $(window).width() - (mousex + tipWidth);
//Distance of element from the bottom of viewport
//var tipVisY = $(window).height() - (mousey + tipHeight);
var tipVisY = $("#mainbody").height() - (tipHeight);
if (tipVisX < 1) { //If tooltip exceeds the X coordinate of viewport
//mousex = e.pageX - tipWidth - 20;
} if (tipVisY < 1) { //If tooltip exceeds the Y coordinate of viewport
//mousey = e.pageY - tipHeight - 20;
}
//Absolute position the tooltip according to mouse position
tip.css({ top: mousey, left: mousex });
}
});
}
}
An alternative is to manually fire the event handler using .trigger('[eventname]'):
$( window ).on( "load", function() {
$( window ).resize(function() {
//do some stuff
}).trigger('resize');
});
As seen in the attached fiddle https://jsfiddle.net/0ws7fws0/5/, user can resize the triangle using north east and south east position.
Below is the code being used
$(document).ready(function() {
var windowWidth = $("#div1").width();
var windowHeight = $("#div1").height();
$(".triangle").css({
"border-top-width": windowWidth / 2 + 'px '
});
$(".triangle").css({
"transform": "rotate(360deg)"
});
$(".triangle").css({
"border-right": windowWidth + 'px solid lightskyblue'
});
$(".triangle").css({
"border-bottom-width": windowWidth / 2 + 'px '
});
$("#div1").draggable({
containment: ".abcde"
});
});
$("#div1").resizable({
handles: "ne,se",
containment: ".abcde",
minHeight: 40,
minWidth: 40
}, {
start: function(e, ui) {
},
resize: function(e, ui) {
var height = Math.round(ui.size.height);
var width = Math.round(ui.size.width);
$(".triangle").css({
"border-top-width": height / 2 + 'px'
});
$(".triangle").css({
"border-bottom-width": height / 2 + 'px'
});
$(".triangle").css({
"border-right": width + 'px solid lightskyblue'
});
$(".triangle").css({
//"margin-top": height + 'px'
});
$(".triangle").css({
"transform": "rotate(360deg)"
});
},
stop: function(e, ui) {
var height = Math.round(ui.size.height);
var width = Math.round(ui.size.width);
}
});
Here user can stretch the triangle but the handle position should be fixed so that the position is not changed even if its resized i.e. ne and se handles can be used to resize but w handle should be fixed(disabled). How do I achieve the same ?
Solution :
What i have done
Break the triangle into two parts: lower and upper
Keep the fixed handle (let's say pin) at same level
Decrease the opp radius when handle(handle use to resize) and pin comes at the same level
See https://jsfiddle.net/0ws7fws0/12/
$(document).ready(function() {
var windowWidth = $("#div1").width();
var windowHeight = $("#div1").height();
$("#div1").draggable({
containment: ".abcde"
});
});
$("#div1").resizable({
handles: "ne,se",
containment: ".abcde",
minHeight: 40,
minWidth: 40
}, {
start: function(e, ui) {
},
resize: function(e, ui) {
var height = Math.round(ui.size.height);
var width = Math.round(ui.size.width);
},
stop: function(e, ui) {
var height = Math.round(ui.size.height);
var width = Math.round(ui.size.width);
var diff = Math.abs(ui.size.height - ui.originalSize.height);
var bottomW = parseInt($(".lower-triangle").css("borderBottomWidth"),10);
var topW = parseInt($(".upper-triangle").css("borderTopWidth"),10);
if (ui.size.height > ui.originalSize.height) {
if($(e.originalEvent.target).hasClass("ui-resizable-se")) {
$(".lower-triangle").css({
"border-bottom-width": (bottomW + diff) + 'px'
});
} else if ($(e.originalEvent.target).hasClass("ui-resizable-ne")) {
$(".upper-triangle").css({
"border-top-width": (topW + diff) + 'px'
});
}
}
else { /*when you compress*/
if($(e.originalEvent.target).hasClass("ui-resizable-se")) {
if ((bottomW - diff)>0) {
$(".lower-triangle").css({
"border-bottom-width": (bottomW - diff) + 'px'
});
}
else {
$(".lower-triangle").css({
"border-bottom-width": '0px'
});
$(".upper-triangle").css({
"border-top-width": ui.size.height + 'px'
});
}
} else if ($(e.originalEvent.target).hasClass("ui-resizable-ne")) {
if ((topW - diff)>0) {
$(".upper-triangle").css({
"border-top-width": (topw - diff) + 'px'
});
}
else {
$(".upper-triangle").css({
"border-top-width": '0px'
});
$(".lower-triangle").css({
"border-bottom-width": ui.size.height + 'px'
});
}
}
}
$(".lower-triangle, .upper-triangle").css({
"border-right": width + 'px solid lightskyblue'
});
}
});
I've tried using jquery's built in draggable and I've tried using custom drag functions with no avail. Both have their respected issues and I will try to highlight both of them.
Basically, I am trying to allow the dragging of an element that is on a scaled div container. The following methods work okay on a scaled element that is less than around 2. But if you go any higher than that, we see some issues.
Any help would be appreciated. Thank you for your time.
HTML
<div id="container">
<div id="dragme">Hi</div>
</div>
Method 1 (Jquery draggable function)
I've tried the jquery draggable function as you can see in this jsfiddle example.
The problems I found in this example are the following:
Biggest concern: The droppable container does not change when it is scaled up. So if the element is being dragged over part of the scaled container that isn't a part of it's original size, it will fail.
When you click to drag a div, it teleports a little bit away from the mouse and is not a seamless drag.
JS
var percent = 2.5;
$("#dragme").draggable({
zIndex: 3000,
appendTo: 'body',
helper: function (e, ui) {
var draggable_element = $(this),
width = draggable_element.css('width'),
height = draggable_element.css('height'),
text = draggable_element.text(),
fontsize = draggable_element.css('font-size'),
textalign = draggable_element.css('font-size');
return $('<div id="' + draggable_element.id + '" name="' + draggable_element.attr('name') + '" class="text">' + text + '</div>').css({
'position': 'absolute',
'text-align': textalign,
'background-color': "red",
'font-size': fontsize,
'line-height': height,
'width': width,
'height': height,
'transform': 'scale(' + percent + ')',
'-moz-transform': 'scale(' + percent + ')',
'-webkit-transform': 'scale(' + percent + ')',
'-ms-transform': 'scale(' + percent + ')'
});
},
start: function (e, ui) {
$(this).hide();
},
stop: function (e, ui) {
$(this).show();
}
});
$("#container").droppable({
drop: function (event, ui) {
var formBg = $(this),
x = ui.offset.left,
y = ui.offset.top,
drag_type = ui.draggable.attr('id');
var element_top = (y - formBg.offset().top - $(ui.draggable).height() * (percent - 1) / 2) / percent,
element_left = (x - formBg.offset().left - $(ui.draggable).width() * (percent - 1) / 2) / percent;
$(ui.draggable).css({
'top': element_top,
'left': element_left
});
}
});
Method 2 - Custom drag function
I've tried using a custom drag function but it unusable after around a 2 scale.
jsfiddle on a scale(2) - Looks like the draggable div is having a seizure.
jsfiddle on a scale(2.5) - The draggable div flys away when you try to drag it.
JS
(function ($) {
$.fn.drags = function (opt) {
opt = $.extend({
handle: "",
cursor: "move"
}, opt);
if (opt.handle === "") {
var $el = this;
} else {
var $parent = this;
var $el = this.find(opt.handle);
}
return $el.css('cursor', opt.cursor).on("mousedown", function (e) {
if (opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
$(this).addClass('active-handle')
var $drag = $parent.addClass('draggable');
}
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
follow = function (e) {
$drag.offset({
top: e.pageY + pos_y - drg_h,
left: e.pageX + pos_x - drg_w
})
};
$(window).on("mousemove", follow).on("mouseup", function () {
$drag.removeClass('draggable');
$(window).off("mousemove", follow);
});
e.preventDefault(); // disable selection
}).on("mouseup", function () {
if (opt.handle === "") {
$(this).removeClass('draggable');
} else {
$(this).removeClass('active-handle');
$parent.removeClass('draggable');
}
});
}
})(jQuery);
$("#dragme").drags({}, function (e) {});
Here are a few of my findings to make sure dragging on a scaled container works for method one. The only caveat is to make sure you have var percent as the scaled percentage declared before any of these actions happen.
First, use this code at the top of your javascript. This wil help making sure that the droppable area works with a sacled container.
$.ui.ddmanager.prepareOffsets = function( t, event ) { var i, j, m = $.ui.ddmanager.droppables[ t.options.scope ] || [], type = event ? event.type : null, list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); droppablesLoop: for ( i = 0; i < m.length; i++ ) { if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { continue; } for ( j = 0; j < list.length; j++ ) { if ( list[ j ] === m[ i ].element[ 0 ] ) { m[ i ].proportions().height = 0; continue droppablesLoop; } } m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; if ( !m[ i ].visible ) { continue; } if ( type === "mousedown" ) { m[ i ]._activate.call( m[ i ], event ); } m[ i ].offset = m[ i ].element.offset(); m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth * percent, height: m[ i ].element[ 0 ].offsetHeight * percent }); } };
Here are a few functions that are necessary to fix the drag so it works on a scaled container.
function dragFix(event, ui) { var changeLeft = ui.position.left - ui.originalPosition.left, newLeft = ui.originalPosition.left + changeLeft / percent, changeTop = ui.position.top - ui.originalPosition.top, newTop = ui.originalPosition.top + changeTop / percent; ui.position.left = newLeft; ui.position.top = newTop; }
function startFix(event, ui) { ui.position.left = 0; ui.position.top = 0; var element = $(this); }
You will want this if you want to enable the element to be resizable on a scaled container.
function resizeFix(event, ui) { var changeWidth = ui.size.width - ui.originalSize.width, newWidth = ui.originalSize.width + changeWidth / percent, changeHeight = ui.size.height - ui.originalSize.height, newHeight = ui.originalSize.height + changeHeight / percent; ui.size.width = newWidth; ui.size.height = newHeight; }
To make an element draggable, I use the following function.
$("ELEMENT").resizable({ minWidth: - ($(this).width()) * 10, minHeight: - ($(this).height()) * 10, resize: resizeFix, start: startFix });
$("ELEMENT").draggable({ cursor: "move", start: startFix, drag: dragFix }); }
A similar problem is mentioned here: jquery - css "transform:scale" affects '.offset()' of jquery
It seems the problem arises from the fact that jQuery fails to return exact size for scaled elements and therefore failing setting right offset values to the element.
To solve this, he is suggesting first setting scale to 1 and setting offset and then again resetting scale value.
But this alone does not solve the problem here. Since mouse position is taken while it is scaled, position values should also be divided by scale value.
Here is an edited version of code:
var scl = 2.5;
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top/scl + drg_h - e.pageY/scl,
pos_x = $drag.offset().left/scl + drg_w - e.pageX/scl;
follow = function(e) {
var size = {
top:e.pageY/scl + pos_y - drg_h+scl*2,
left:e.pageX/scl + pos_x - drg_w+scl*2
};
$drag.parent().css("transform","scale(1)");
$drag.offset(size);
$drag.parent().css("transform","scale("+scl+")");
};
Note: I only replaced scale value for transform tag, since I am using chrome. You can also replace all instances or instead you can use a different class with 1 scale value.
JSFiddle is also here.
Here is an example of simple drag with scaling, however, in prue dom.
<style>
#dragme {
position:absolute;
border:1px solid red;
background:pink;
left:10px;
top:20px;
width:100px;
height:200px;
}
#container {
transform: scale(2,2) translate(100px,100px);
position:relative;
border:1px solid green;
background:grey;
width:200px;
height:300px;
}
</style>
<body>
<div id="container">
<div id="dragme">Hi</div>
</div>
<script>
var dragme=document.getElementById("dragme");
var container=document.getElementById("container");
dragme.onmousedown=function Drag(e){
this.ini_X = this.offsetLeft-e.clientX/2;
this.ini_Y = this.offsetTop-e.clientY/2;
container.onmousemove = move;
container.onmouseup = release;
return false;
}
function move(e){
e.target.style.left = e.clientX/2 + e.target.ini_X + 'px';
e.target.style.top = e.clientY/2 + e.target.ini_Y + 'px';
}
function release(){
container.onmousemove=container.onmouseup=null;
}
</script>
</body>
I'm trying to write jQuery plugin which replace default cursor to necessary image, but I have a problem with mouseleave. It doesn't fire because cursor always before child div and never leave it, so cursor never changes back to default.
DEMO
Any ideas how to fix it?
By the way: jQuery mouseleave behavior is little strange. It fires only when you leave your div and all childe divs.
DEMO 2
My code:
// Plugin changing cursor before element
;
(function ($) {
$.fn.changeCursor = function (cursorPicUrl, dx, dy) {
function inFunction(e) {
$cursor.show();
return false;
}
function outFunction(e) {
$cursor.hide();
return false;
}
function moveFunction(e) {
var x = e.clientX-100;
var y = e.clientY-100;
$cursor.css({
"transform": "translate(" + x + "px," + y + "px)"
});
}
var $cursor = $('<div id="#custom-cursor"></div>').css({
/*cursor: none;*/
width: '150px',
height: '150px',
background: 'url("' + cursorPicUrl + '") no-repeat left top',
position: 'absolute',
display: 'none',
'z-index': '10000'
});
this.append( $cursor )
.on( "mouseenter", inFunction )
.on( "mouseleave", outFunction )
//.hover( inFunction, outFunction)
.mousemove( moveFunction );
return this;
};
})(jQuery);
$(document).ready(function () {
var url = 'http://placehold.it/150x150';
$('#test-area').changeCursor( url );
});
UPDATE
My solition here:
jquery.change-cursor
I made a couple of adjustments:
Store this in a variable up front.
Attach the cursor div to the body.
Add the top/left properties to the cursor.
DEMO
Javascript:
(function ($) {
$.fn.changeCursor = function (cursorPicUrl, dx, dy) {
var elem = this;
function inFunction(e) {
$cursor.show();
return false;
}
function outFunction(e) {
$cursor.hide();
return false;
}
function moveFunction(e) {
var x = e.clientX;
var y = e.clientY;
$cursor.css({
"transform": "translate(" + x + "px," + y + "px)"
});
}
var $cursor = $('<div id="#custom-cursor"></div>').css({
/*cursor: none;*/
width: '150px',
height: '150px',
background: 'url("' + cursorPicUrl + '") no-repeat left top',
position: 'absolute',
top: '0',
left: '0',
display: 'none'
});
$('body').append( $cursor );
elem.on( "mouseenter", inFunction )
.on( "mouseleave", outFunction )
.mousemove( moveFunction );
return this;
};
})(jQuery);
For anyone still looking something similar, try this (maybe):
$('#selector').css('cursor', 'url("/path/your_image.png"), auto');
PS: Doesn't work on primitive browsers!