I am trying to build a seating reservation web app using SVG. Imagine, I've created rectangles in the svg, which represents an empty seat. I want to allow user to drop an html "image" element on the "rect" to reserve the seat.
However, I couldn't get the droppable to work on the SVG elemnets. Any one has any idea why this is so? Here is the code:
$('#target').svg();
var svg = $("#target").svg('get');
svg.rect(20, 10, 100, 50, 10, 10, { fill: '#666', class: "droppable" });
$('rect')
.droppable({
accept: '.product',
tolerance: 'touch',
drop: function (event, ui) {
alert('df');
}
}
I looked in to the jQuery-ui source and figured out why it wasn't working with SVGs. jQuery thinks they have a width and height of 0px, so the intersection test fails.
I wrapped $.ui.intersect and set the correct size information before passing the arguments through to the original function. There may be more proportion objects that need fixing but the two I did here are enough to fix my :
$.ui.intersect_o = $.ui.intersect;
$.ui.intersect = function(draggable, droppable, toleranceMode) {
//Fix helper
if (draggable.helperProportions && draggable.helperProportions.width === 0 && draggable.helperProportions.height === 0) {
draggable.helperProportionsBBox = draggable.helperProportionsBBox || $(draggable.element).get(0).getBBox();
draggable.helperProportions = draggable.helperProportionsBBox;
}
//Fix droppable
if (droppable.proportions && droppable.proportions.width === 0 && droppable.proportions.height === 0) {
droppable.proportionsBBox = droppable.proportionsBBox || $(droppable.element).get(0).getBBox();
droppable.proportions = droppable.proportionsBBox;
}
return $.ui.intersect_o(draggable, droppable, toleranceMode);
};
With jQuery UI 1.11.4 I had to change Eddie's solution to the following, as draggable.proportions is now a function:
$.ui.intersect_o = $.ui.intersect;
$.ui.intersect = function (draggable, droppable, toleranceMode, event) {
//Fix helper
if (draggable.helperProportions && draggable.helperProportions.width === 0 && draggable.helperProportions.height === 0) {
draggable.helperProportionsBBox = draggable.helperProportionsBBox || $(draggable.element).get(0).getBBox();
draggable.helperProportions = draggable.helperProportionsBBox;
}
if (droppable.proportions && !droppable.proportions().width && !droppable.proportions().height)
if (typeof $(droppable.element).get(0).getBBox === "function") {
droppable.proportionsBBox = droppable.proportionsBBox || $(droppable.element).get(0).getBBox();
droppable.proportions = function () {
return droppable.proportionsBBox;
};
}
return $.ui.intersect_o(draggable, droppable, toleranceMode, event);
};
If you want to restrict the drop on svg elements to hit on visible content only (for example in polygons ) you might want to use this addition to Peter Baumann's suggestion:
$.ui.intersect_o = $.ui.intersect;
$.ui.intersect = function (draggable, droppable, toleranceMode, event) {
//Fix helper
if (draggable.helperProportions && draggable.helperProportions.width === 0 && draggable.helperProportions.height === 0) {
draggable.helperProportionsBBox = draggable.helperProportionsBBox || $(draggable.element).get(0).getBBox();
draggable.helperProportions = draggable.helperProportionsBBox;
}
if (droppable.proportions && !droppable.proportions().width && !droppable.proportions().height)
if (typeof $(droppable.element).get(0).getBBox === "function") {
droppable.proportionsBBox = droppable.proportionsBBox || $(droppable.element).get(0).getBBox();
droppable.proportions = function () {
return droppable.proportionsBBox;
};
}
var intersect = $.ui.intersect_o(draggable, droppable, toleranceMode, event);
if (intersect) {
var dropTarget = $(droppable.element).get(0);
if (dropTarget.ownerSVGElement && (typeof (dropTarget.isPointInFill) === 'function') && (typeof (dropTarget.isPointInStroke) === 'function')) {
var x = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left + draggable.helperProportions.width / 2,
y = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top + draggable.helperProportions.height / 2,
p = dropTarget.ownerSVGElement.createSVGPoint();
p.x = x;
p.y = y;
p = p.matrixTransform(dropTarget.getScreenCTM().inverse());
if(!(dropTarget.isPointInFill(p) || dropTarget.isPointInStroke(p)))
intersect = false;
}
}
return intersect;
};
In case if anyone has the same question in mind, droppable doesn't work in jquery SVG. So in the end, I did the following to create my own droppable event:
In draggable, set the target currently dragged been dragged to draggedObj ,
In the mouse up event, check if the draggedObj is null, if it's not null, then drop the item according to the current position. ( let me know if you need help on detecting the current position)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.