JQuery Draggable: Is it possible to snap to grid after mouse release? - jquery-ui

Basically, i want to use the grid option to snap a draggable div toa 30 x 30 grid but i want to keep the dragging smooth. So is there a way i can snap to the grid on mouse release (or something similar)

correction to #Zed
this will use the center for deciding which grid to place it in. which ever most of the draggable is in is the one it goes.
stop: function(e, ui) {
var grid_x = 30;
var grid_y = 30;
var elem = $( this );
var left = parseInt(elem.css('left'));
var top = parseInt(elem.css('top'));
var cx = (left % grid_x);
var cy = (top % grid_y);
var new_left = (Math.abs(cx)+0.5*grid_x >= grid_x) ? (left - cx + (left/Math.abs(left))*grid_x) : (left - cx);
var new_top = (Math.abs(cy)+0.5*grid_y >= grid_y) ? (top - cy + (top/Math.abs(top))*grid_y) : (top - cy);
ui.helper.stop(true).animate({
left: new_left,
top: new_top,
opacity: 1,
}, 200);
},

If that is all you want to do with the grid, you could emulate it:
$("#myobj").draggable({
...
stop: function(event, ui) {
t = parseInt($(this).css(top);
l = parseInt($(this).css(left);
$(this).css(top , t - t % 30);
$(this).css(left, l - l % 30);
}
...
});

Try transition!
A nice little something I just discovered now is, that if you give the dragged element the css property of transition it will have an effect on the speed it snaps to grid.
$(function() {
$(".draggable").draggable({
containment: 'window',
grid: [30, 30]
});
});
.draggable {
background: #333;
color: whitesmoke;
font-family: 'sans-serif', 'arial';
padding: 5px 12px;
display: inline-block;
transition: top 0.05s ease-in-out, left 0.05s ease-in-out
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div class="draggable">Drag Me!</div>

Related

How to move point's label and SVGs by moving a point graphic in highcharts gantt?

In this example, I tried to move the points by points.graphic.translate(0, -25), but it can't help to move point's label and SVGs. You can see the details in the example.
events: {
load() {
var chart = this,
series = chart.series[0];
series.points.forEach(function(point) {
point.graphic.translate(0, -25);
});
}
}
You need to move each element separately.
Label:
point.dataLabel.text.translate(0, -25)
And custom image just after rendering it:
points.forEach(function(point) {
point.customImg = chartt.renderer.image(
'https://www.highcharts.com/images/employees2014/Torstein.jpg',
point.plotX + chartt.plotLeft + point.shapeArgs.width / 2 - width / 2,
point.plotY + chartt.plotTop - height / 2,
width,
height
)
.attr({
zIndex: 5
})
.add();
point.customImg.translate(0, -25)
});
Demo: https://jsfiddle.net/BlackLabel/05hmufxa/

KonvaJS crop and resize

I'm using KonvaJS to create a simple Image-Editor. As a base for the image resize function I used the code from the Konva Examples (Knonva JS Image Resize). But now I'm struggling with the implementation of a crop function. On a button click, I enable the user to draw a rectangle on the stage. I then use the built-in crop function on my image with the coordinates, width and height of the drawn rectangle and crop the image. But when I resize the image before I crop it the cropped area shows the part cropped from the original sized image.
Is there an easy, build in way I'm missing to be able to crop from the resized image? Or do I have to calculate the position and size of the drawn rectangle according to the resized values of the image, then crop that part and resize and reposition the result?
Crop Image:
function cropImage(x, y, width, height, activeLayer) {
var image = activeLayer.get('Image')[0], xDiff = 0, yDiff = 0, newWidth, newHeight, newX, newY;
// only Crop visible Parts of the Image
if(x < activeLayer.getX()) {
xDiff = activeLayer.getX() - x;
}
if(y < activeLayer.getY()) {
yDiff = activeLayer.getY() - y;
}
if (x + width > activeLayer.getX() + activeLayer.width()) {
width = width - ((x + width) - (activeLayer.getX() + activeLayer.width()));
}
if (y + height > activeLayer.getY() + activeLayer.height()) {
height = height - ((y + height) - (activeLayer.getY() + activeLayer.height()));
}
newHeight = height - yDiff;
newWidth = width - xDiff;
newX = (x - activeLayer.getX()) + image.cropX() + xDiff;
newY = (y - activeLayer.getY()) + image.cropY() + yDiff;
image.width(newWidth);
image.height(newHeight);
activeLayer.width(newWidth);
activeLayer.height(newHeight);
activeLayer.setX(newX + activeLayer.getX() - image.cropX());
activeLayer.setY(newY + activeLayer.getY() - image.cropY());
image.crop({
x : newX ,
y : newY ,
width : newWidth,
height : newHeight
});
//Reposition anchors so topLeft Anchor is always in 0/0 of the grouplayer
repositionAnchors(activeLayer);
activeLayer.draw();
}
This is not yet a precise answer to your question but I am including here because it might show the way for you or others in the same territory of cropping.
Run the snippet full screen.
Left image is Konva, right is the original image.
Click-drag on the left image to make a selection. The left image changes to be the selection only whilst the right shows the position of the crop. Repeat the process to see how the crops build up.
I have NOT scaled the image on the canvas in this example, so it is not an exact answer to your needs at present, but useful for visualising what is happening. I can add scaling if folks think it would be useful.
// Useful frequently used variables.
var sX = 0, sY = 0, sW = 400, sH = 200; // drawing dimensions
var iW = 0, iH = 0; // image dimensions
var cropRect = {x: sX, y: sY, width: iW, height: iH}; // scaled rect
var imgRect = $('.imgRect');
var imgPtr = $('#imgPtr');
var scale = 1;
var img = $('#daImg');
var src = "https://dummyimage.com/400x200/e85de8/fff&text=SO Rocks!"
$('.container').css({width: sW, height: sH});
// Vars for mouse rect work.
var posStart, posNow, mode = '';
// Set up add a stage & layer
var s1 = new Konva.Stage({container: 'container', width: sW, height: sH});
var l1 = new Konva.Layer({});
s1.add(l1);
var image = new Konva.Image({}) // prepare an image to display the picture.
l1.add(image);
// I use a foreground rect to catch events - this covers the konva image completely - you can wire your events in your own way
var r1 = new Konva.Rect({x: 0, y: 0, width: sW, height: sH, fill: 'gold', opacity: 0 })
l1.add(r1)
// draw a rectangle to be used as the rubber-band area
var r2 = new Konva.Rect({x: 0, y: 0, width: 0, height: 0, stroke: 'red', dash: [2,2]})
r2.listening(false); // stop r2 catching our mouse events otherwise if we reverse mouse direction events may not fire
l1.add(r2)
// Mouse movement funcs
function startDrag(posIn){
posStart = {x: posIn.x, y: posIn.y};
posNow = {x: posIn.x, y: posIn.y};
}
// update rubber rect position
function updateDrag(posIn){
posNow = {x: posIn.x, y: posIn.y};
var posRect = reverse(posStart,posNow);
r2.x(posRect.x1);
r2.y(posRect.y1);
r2.width(posRect.x2 - posRect.x1);
r2.height(posRect.y2 - posRect.y1);
r2.visible(true);
s1.draw(); // redraw any changes.
sayRect(r2);
showImgRect(r2);
}
// start the rubber rect drawing on mouse down.
r1.on('mousedown', function(e){
mode = 'drawing';
startDrag({x: e.evt.layerX, y: e.evt.layerY})
})
// update the rubber rect on mouse move - note use of 'mode' var to avoid drawing after mouse released.
r1.on('mousemove', function(e){
if (mode === 'drawing'){
updateDrag({x: e.evt.layerX, y: e.evt.layerY})
}
showImgPtr(e.evt.layerX, e.evt.layerY);
sayPos(e.evt.layerX, e.evt.layerY);
})
// When user releases the mouse we note the size and modify the clip rect.
r1.on('mouseup', function(e){
mode = '';
r2.visible(false);
// leave a rect to show the target
imgRect.hide();
var imgRect2 = imgRect.clone();
imgRect2
.appendTo('#container2')
.addClass('deleteMe')
.show();
setCrop(r2);
sayInfo(img, image);
})
// Draw a rect on the original image to show location and size. Just using some simple jquery to manipulate a div.
function showImgRect(r){
imgRect.css({
left: r.x() + cropRect.x,
top: r.y() + cropRect.y,
width: r.width() * 1,
height: r.height() * 1
})
imgRect.show();
}
// show a mouse pointer on the original image so we get a sense of what is going on
function showImgPtr(x, y){
imgPtr.css({ left: cropRect.x + x, top: cropRect.y + y})
}
// Set the new crop rect, taking account of previous crops
function setCrop(r){
image.cropX(r.x() + cropRect.x);
image.cropY(r.y() + cropRect.y);
image.cropWidth(r.width() * scale);
image.cropHeight(r.height() * scale);
image.width(r.width());
image.height(r.height());
l1.draw();
cropRect = {x: cropRect.x + r.x(), y: cropRect.y + r.y(), width: r.width(), height: r.height()};
}
// This event listener is fired when the image is loaded - could be a few secs delay for a big image
// so this is effectively an async technique.
img.on('load', function() {
// note the dimensions
iW = img.width();
iH = img.height();
// set the konva image details
image.x(sX);
image.y(sY);
image.width(iW);
image.height(iH);
image.image(img[0]);
sayInfo(img, image);
l1.draw(); // redraw the layer to see what happened
});
// This innocent looking line intiates the image load and ultimately fires the event above.
img.prop('src', src);
/*
From here down is utility stuff
*/
// Say something useful
function sayInfo(img, image){
$('#imgInfo').html("HTML Image size " + img.width() + " x " + img.height());
$('#imageInfo').html("Konva.image " + image.x() + ", " + image.y() + " - " + image.width() + " x " + image.height());
var info = $('#info');
}
function sayRect(r){
var rectInfo = $('#rectInfo');
rectInfo.html("Clip rect on canvas " + r.x() + ", " + r.y() + " - " + r.width() + " x " + r.height());
}
function sayPos(x, y){
var posInfo = $('#posInfo');
posInfo.html("Pos on stage " + x + ", " + y);
}
// This is just to reverse co-ords if user drags left / up
function reverse(r1, r2){
var r1x = r1.x, r1y = r1.y, r2x = r2.x, r2y = r2.y, d;
if (r1x > r2x ){
d = Math.abs(r1x - r2x);
r1x = r2x; r2x = r1x + d;
}
if (r1y > r2y ){
d = Math.abs(r1y - r2y);
r1y = r2y; r2y = r1y + d;
}
return ({x1: r1x, y1: r1y, x2: r2x, y2: r2y}); // return the corrected rect.
}
// reset function
function reset(){
sX = 0; sY = 0; sW = 400; sH = 300; // drawing dimensions
iW = 0; iH = 0; // image dimensions
iW = img.width();
iH = img.height();
cropRect = {x: sX, y: sY, width: iW, height: iH}; // scaled rect
scale = 1;
if (image){
console.log('iH=' +iH);
image.x(sX);
image.y(sY);
image.width(iW);
image.height(iH);
image.cropX(sX);
image.cropY(sY);
image.cropWidth(iW);
image.cropHeight(iH);
}
$('.deleteMe').remove();
$('.imgRect').hide();
l1.draw();
}
$('#reset').on('click', function(){reset()});
p
{
padding: 5px;
}
.container {
position: relative;
display: inline-block;
width: 500px;
height: 400px;
background-color: transparent;
overflow: hidden;
border: 1px solid silver;
}
.imgRect {
position: absolute;
border: 1px dotted red;
background-color: Aqua;
opacity: 0.3;
}
#imgPtr {
position: absolute;
background-color: red;
width: 1px;
height: 1px;
border-radius: 50%;
border: 2px solid red;
}
a {
color: red;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<p>
<span id='text'>How crop rect relates to original image. First image is the Konva stage, second is the original image. Use click and drag to draw successive rects on the Konva image.</span> <a id='reset'>Reset</a>
</p>
<p>
<span id='imgInfo'></span><br />
<span id='imageInfo'></span>
<span id='rectInfo'>Rect info </span><br/>
<span id='posInfo'>Pos on stage </span><br/>
<span id='scaleInfo'>Scale 1:1 </span>
</p>
<div id='container' class='container'></div>
<div id='container2' class='container'>
<img id='daImg' />
<div class='imgRect'></div>
<div id='imgPtr'></div>
</div>
When resizing i preserve the ratio for width and height in an array and calculate the position and dimension of the rectangle which is drawn for the crop :
cropX = ((x / ratios[id].width) - (activeLayer.getX() / ratios[id].width)) + (image.cropX()) + (xDiff / ratios[id].width);
cropY = ((y / ratios[id].height)- (activeLayer.getY() / ratios[id].height)) + (image.cropY()) + (yDiff / ratios[id].height);
cropWidth = (width / ratios[id].width) - (xDiff / ratios[id].width),
cropHeight = (height / ratios[id].height) - (yDiff / ratios[id].height)

Konvajs Clipping function but with opacity

I've been using the Konvajs clipping function to limit what can be seen inside a bounding box.
Has anyone managed to write a similar function but when the konva object leaves the bounding box it changes in opacity instead of simply not being seen?
Thanks for the input.
Here's a working version. The yellow region is the canvas extent. The clear image in the center is the clipping region. The semi-transparent region is the full extent of the image. Click & drag the clipped region and you can see the 'clipped off' component of the image displayed.
// this is the position for the clipping rectangle
var clipRect = {left: 30, top: 30, width : 420, height : 340, right: 450, bottom: 390};
// generic
// add a stage & add a layer
var s = new Konva.Stage({container: 'container', width: 800, height: 600});
var l = new Konva.Layer({draggable: true});
// background layer
var bgr = new Konva.Rect({x:0, y: 0, width: 500, height: 500, fill: 'gold', opacity: 0.1, listening: false})
l.add(bgr)
s.add(l);
// end of generic
// Add an image to show the full extent of the clipped image
var boundsRect = new Konva.Image({opacity: 0.2, stroke: 'black', strokeWidth: 1, draggable: false, dash: [2, 2], listening: false});
l.add(boundsRect);
// to clip we have to add a group with a clip.
var vp = new Konva.Group({
clip: { x: clipRect.left, y: clipRect.top, width : clipRect.width, height : clipRect.height}
});
// add a border to the clip region via a rect just surrounding it.
var r1 = new Konva.Rect({x: clipRect.left - 1, y: clipRect.top - 1, width : clipRect.width + 2, height : clipRect.height + 2, stroke: '#00008B', strokeWidth: 1, draggable: false});
l.add(r1);
/* This is the image that is the subject of the clipping effort */
var i=new Konva.Image({x: 0, y: 0, width: 0, height: 0, draggable: true,
// we want to ensure that the image cannot be dragged
// beyond the glip rect bounds.
dragBoundFunc: function(pos) {
var posRect = getPosRect(pos,this);
var iPos = this.getClientRect();
var newX = pos.x;
var newY = pos.y;
newX = (posRect.left >= clipRect.left) ? clipRect.left : posRect.left;
newX = (posRect.right <= clipRect.right) ? clipRect.right - posRect.width : newX;
newY = (posRect.top >= clipRect.top) ? clipRect.top : posRect.top;
newY = (posRect.bottom <= clipRect.bottom) ? clipRect.bottom - posRect.height : newY;
return {
x: newX,
y: newY
}}
});
i.on('dragmove', function() {
setBoundRect(this);
});
vp.add(i);
var imageObj = new Image();
imageObj.onload=function () {
i.image(imageObj);
boundsRect.image(imageObj);
i.width(imageObj.width);
i.height(imageObj.height);
setBoundRect(i);
s.draw();
}
imageObj.src = "http://btckstorage.blob.core.windows.net/site13706/gallery/2015/Porthleven%20lifeboat%20day%202015%20f%20-%20Chris%20Yacoubian%20Ltd.jpg";
l.add(vp) // add image to clipping viewport
s.draw()
// used to get the client rect of a shape.
function getPosRect(pos, ele){
var cliPos = ele.getClientRect();
var posRect = {left: pos.x, top: pos.y, right: pos.x + cliPos.width, bottom: pos.y + cliPos.height, width: cliPos.width, height: cliPos.height};
return posRect;
}
// set the bounds rect to the size of the given element
function setBoundRect(ele){
var x = ele.position();
var posRect = getPosRect(ele.position(), ele);
boundsRect.position({x: posRect.left, y: posRect.top});
boundsRect.size({width: posRect.width, height: posRect.height});
}
// change the image
$('img').on("click", function(e){
imageObj.src = $(this).prop("src");
})
.pic
{
max-width:150px;
max-height: 80px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<div id='container' style="display: inline-block; width: 750px; height: 400px; background-color: transparent; overflow: hidden;"></div>
<div style="display: inline-block; width: 500px; height: 400px; " >
<p>
<img class='pic' src="http://btckstorage.blob.core.windows.net/site13706/gallery/2015/53%20-%20Chris%20Yacoubian%20Ltd.jpg"/>
</p>
<p>
<img class='pic'src="http://btckstorage.blob.core.windows.net/site13706/gallery/2015/Crew%20day%20Mousehole%202015%20e%20-%20Chris%20Yacoubian%20Ltd.jpg" />
</p>
<p>
<img class='pic' src="http://btckstorage.blob.core.windows.net/site13706/gallery/2015/34%20-%20Chris%20Yacoubian%20Ltd.jpg"/>
</p>

Highcharts navigator handle height

Is there any way to increase the height of the handles in the highstock navigator component? Right now, the only options available are to change the color and the border-color. How about the height and width of the handles?
http://api.highcharts.com/highstock#navigator.handles
Thanks,
Vikas.
You can wrap drawHandles function and modify it to have increased height.
var height = 20;
(function (H) {
H.wrap(H.Scroller.prototype, 'drawHandle', function (proceed, x, index) {
var scroller = this,
chart = scroller.chart,
renderer = chart.renderer,
elementsToDestroy = scroller.elementsToDestroy,
handles = scroller.handles,
handlesOptions = scroller.navigatorOptions.handles,
attr = {
fill: handlesOptions.backgroundColor,
stroke: handlesOptions.borderColor,
'stroke-width': 1
},
tempElem;
// create the elements
if (!scroller.rendered) {
// the group
handles[index] = renderer.g('navigator-handle-' + ['left', 'right'][index])
.css({
cursor: 'e-resize'
})
.attr({
zIndex: 4 - index
}) // zIndex = 3 for right handle, 4 for left
.add();
// the rectangle
tempElem = renderer.rect(-4.5, 0, 9, height, 0, 1)
.attr(attr)
.add(handles[index]);
elementsToDestroy.push(tempElem);
// the rifles
tempElem = renderer.path([
'M', -1.5, 4,
'L', -1.5, 12,
'M',
0.5, 4,
'L',
0.5, 12]).attr(attr)
.add(handles[index]);
elementsToDestroy.push(tempElem);
}
// Place it
handles[index][chart.isResizing ? 'animate' : 'attr']({
translateX: scroller.scrollerLeft + scroller.scrollbarHeight + parseInt(x, 10),
translateY: scroller.top + scroller.height / 2 - 8
});
});
}(Highcharts));
http://jsfiddle.net/za68w54r/
There is an option for increasing the height of the navigator too..
Check this fiddle:
http://jsfiddle.net/gh/get/jquery/1.7.2/highslide-software/highcharts.com/tree/master/samples/stock/navigator/height/
Code:
navigator: {
height: 100
},

highcharts datalabel dynamic rotation as column height

As you can see in the picture each column is accompanied by its datalabels, all is well. The detail is when small amounts and their datalabels is misconfigured with the categories, as seen in the picture (Red square). What I want to do is check if your height is less, to change its rotation from -90 to 0 (Green letters)
See picture of the solution (HighCharts) here:
https://docs.google.com/file/d/0B93NeaQX1VjUMldzcGIxNnBqaWc/edit
See code JSFiddle of my solution (HighCharts) here :
http://jsfiddle.net/bryan376/325dev4h/1/
This is my code push of series:
options.series.push({
name: 'Vendedor',
data: arrFinal,
dataLabels: {
enabled: true,
rotation: -90, //Validation height < 70 "rotation=0" else rotation=-90
color: 'black',
align: 'right',
x: 4,
y: 10,
style: {
fontSize: '11px',
fontFamily: 'Verdana, sans-serif'
}
}
});
var chart = new Highcharts.Chart(options);
}
Greetings
You can change Highcharts.Series.prototype.drawDataLabels, the function to draw the dataLabels:
Highcharts.Series.prototype.drawDataLabels = (function (func) {
return function () {
func.apply(this, arguments);
if (this.options.dataLabels.enabled || this._hasPointLabels) realignLabels(this);
};
}(Highcharts.Series.prototype.drawDataLabels));
realignLabels would be the function to check for the shorter columns, and in it change the rotation, x and y of that specific dataLabel:
function realignLabels(serie) {
$.each(serie.points, function (j, point) {
if (!point.dataLabel) return true;
var max = serie.yAxis.max,
labely = point.dataLabel.attr('y'),
labelx = point.dataLabel.attr('x');
if (point.y / max < 0.05) {
point.dataLabel.attr({
y: labely - 20,
x: labelx + 5,
rotation: 0
});
}
});
};
http://jsfiddle.net/325dev4h/7

Resources