Downgraded svg.js as many plugins did not support v3.x

Now rooms can be moved and resized.
This commit is contained in:
Ziver Koc 2023-01-10 02:58:36 +01:00
parent fb7f43ed23
commit b80991280a
12 changed files with 6266 additions and 7226 deletions

View file

@ -1,24 +1,4 @@
.selection_border {
fill: none;
stroke: black;
stroke-width:1;
}
.selection_handle_shear {
fill: white;
stroke: black;
stroke-width:1;
}
.selection_handle_rot {
fill: white;
stroke: black;
stroke-width:1;
}
/* .svg_select_points_lt{
.svg_select_points_lt{
cursor: nw-resize;
}
.svg_select_points_rt{
@ -61,4 +41,4 @@
stroke-opacity:0.8;
fill-opacity:0.1;
pointer-events:none; /* This ons is needed if you want to deselect or drag the shape*/
/*} */
}

View file

@ -1,177 +1,235 @@
/*!
* @svgdotjs/svg.draggable.js - An extension for svg.js which allows to drag elements with your mouse
* @version 3.0.2
/*! svg.draggable.js - v2.2.2 - 2019-01-08
* https://github.com/svgdotjs/svg.draggable.js
*
* @copyright Wout Fierens
* @license MIT
*
* BUILT: Tue Feb 19 2019 17:12:16 GMT+0100 (GMT+01:00)
*/;
(function (svg_js) {
'use strict';
* Copyright (c) 2019 Wout Fierens; Licensed MIT */
;(function() {
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
// creates handler, saves it
function DragHandler(el){
el.remember('_draggable', this)
this.el = el
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
// Sets new parameter, starts dragging
DragHandler.prototype.init = function(constraint, val){
var _this = this
this.constraint = constraint
this.value = val
this.el.on('mousedown.drag', function(e){ _this.start(e) })
this.el.on('touchstart.drag', function(e){ _this.start(e) })
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
// transforms one point from screen to user coords
DragHandler.prototype.transformPoint = function(event, offset){
event = event || window.event
var touches = event.changedTouches && event.changedTouches[0] || event
this.p.x = touches.clientX - (offset || 0)
this.p.y = touches.clientY
return this.p.matrixTransform(this.m)
}
var getCoordsFromEvent = function getCoordsFromEvent(ev) {
if (ev.changedTouches) {
ev = ev.changedTouches[0];
// gets elements bounding box with special handling of groups, nested and use
DragHandler.prototype.getBBox = function(){
var box = this.el.bbox()
if(this.el instanceof SVG.Nested) box = this.el.rbox()
if (this.el instanceof SVG.G || this.el instanceof SVG.Use || this.el instanceof SVG.Nested) {
box.x = this.el.x()
box.y = this.el.y()
}
return {
x: ev.clientX,
y: ev.clientY
};
}; // Creates handler, saves it
return box
}
// start dragging
DragHandler.prototype.start = function(e){
var DragHandler =
/*#__PURE__*/
function () {
function DragHandler(el) {
_classCallCheck(this, DragHandler);
el.remember('_draggable', this);
this.el = el;
this.drag = this.drag.bind(this);
this.startDrag = this.startDrag.bind(this);
this.endDrag = this.endDrag.bind(this);
} // Enables or disabled drag based on input
_createClass(DragHandler, [{
key: "init",
value: function init(enabled) {
if (enabled) {
this.el.on('mousedown.drag', this.startDrag);
this.el.on('touchstart.drag', this.startDrag);
} else {
this.el.off('mousedown.drag');
this.el.off('touchstart.drag');
}
} // Start dragging
}, {
key: "startDrag",
value: function startDrag(ev) {
var isMouse = !ev.type.indexOf('mouse'); // Check for left button
if (isMouse && (ev.which || ev.buttons) !== 1) {
return;
} // Fire beforedrag event
if (this.el.dispatch('beforedrag', {
event: ev,
handler: this
}).defaultPrevented) {
return;
} // Prevent browser drag behavior as soon as possible
ev.preventDefault(); // Prevent propagation to a parent that might also have dragging enabled
ev.stopPropagation(); // Make sure that start events are unbound so that one element
// is only dragged by one input only
this.init(false);
this.box = this.el.bbox();
this.lastClick = this.el.point(getCoordsFromEvent(ev)); // We consider the drag done, when a touch is canceled, too
var eventMove = (isMouse ? 'mousemove' : 'touchmove') + '.drag';
var eventEnd = (isMouse ? 'mouseup' : 'touchcancel.drag touchend') + '.drag'; // Bind drag and end events to window
svg_js.on(window, eventMove, this.drag);
svg_js.on(window, eventEnd, this.endDrag); // Fire dragstart event
this.el.fire('dragstart', {
event: ev,
handler: this,
box: this.box
});
} // While dragging
}, {
key: "drag",
value: function drag(ev) {
var box = this.box,
lastClick = this.lastClick;
var currentClick = this.el.point(getCoordsFromEvent(ev));
var x = box.x + (currentClick.x - lastClick.x);
var y = box.y + (currentClick.y - lastClick.y);
var newBox = new svg_js.Box(x, y, box.w, box.h);
if (this.el.dispatch('dragmove', {
event: ev,
handler: this,
box: newBox
}).defaultPrevented) return;
this.move(x, y);
return newBox;
// check for left button
if(e.type == 'click'|| e.type == 'mousedown' || e.type == 'mousemove'){
if((e.which || e.buttons) != 1){
return
}
}, {
key: "move",
value: function move(x, y) {
// Svg elements bbox depends on their content even though they have
// x, y, width and height - strange!
// Thats why we handle them the same as groups
if (this.el.type === 'svg') {
svg_js.G.prototype.move.call(this.el, x, y);
} else {
this.el.move(x, y);
}
var _this = this
// fire beforedrag event
this.el.fire('beforedrag', { event: e, handler: this })
if(this.el.event().defaultPrevented) return;
// prevent browser drag behavior as soon as possible
e.preventDefault();
// prevent propagation to a parent that might also have dragging enabled
e.stopPropagation();
// search for parent on the fly to make sure we can call
// draggable() even when element is not in the dom currently
this.parent = this.parent || this.el.parent(SVG.Nested) || this.el.parent(SVG.Doc)
this.p = this.parent.node.createSVGPoint()
// save current transformation matrix
this.m = this.el.node.getScreenCTM().inverse()
var box = this.getBBox()
var anchorOffset;
// fix text-anchor in text-element (#37)
if(this.el instanceof SVG.Text){
anchorOffset = this.el.node.getComputedTextLength();
switch(this.el.attr('text-anchor')){
case 'middle':
anchorOffset /= 2;
break
case 'start':
anchorOffset = 0;
break;
}
}
this.startPoints = {
// We take absolute coordinates since we are just using a delta here
point: this.transformPoint(e, anchorOffset),
box: box,
transform: this.el.transform()
}
// add drag and end events to window
SVG.on(window, 'mousemove.drag', function(e){ _this.drag(e) })
SVG.on(window, 'touchmove.drag', function(e){ _this.drag(e) })
SVG.on(window, 'mouseup.drag', function(e){ _this.end(e) })
SVG.on(window, 'touchend.drag', function(e){ _this.end(e) })
// fire dragstart event
this.el.fire('dragstart', {event: e, p: this.startPoints.point, m: this.m, handler: this})
}
// while dragging
DragHandler.prototype.drag = function(e){
var box = this.getBBox()
, p = this.transformPoint(e)
, x = this.startPoints.box.x + p.x - this.startPoints.point.x
, y = this.startPoints.box.y + p.y - this.startPoints.point.y
, c = this.constraint
, gx = p.x - this.startPoints.point.x
, gy = p.y - this.startPoints.point.y
this.el.fire('dragmove', {
event: e
, p: p
, m: this.m
, handler: this
})
if(this.el.event().defaultPrevented) return p
// move the element to its new position, if possible by constraint
if (typeof c == 'function') {
var coord = c.call(this.el, x, y, this.m)
// bool, just show us if movement is allowed or not
if (typeof coord == 'boolean') {
coord = {
x: coord,
y: coord
}
}
}, {
key: "endDrag",
value: function endDrag(ev) {
// final drag
var box = this.drag(ev); // fire dragend event
this.el.fire('dragend', {
event: ev,
handler: this,
box: box
}); // unbind events
svg_js.off(window, 'mousemove.drag');
svg_js.off(window, 'touchmove.drag');
svg_js.off(window, 'mouseup.drag');
svg_js.off(window, 'touchend.drag'); // Rebind initial Events
this.init(true);
// if true, we just move. If !false its a number and we move it there
if (coord.x === true) {
this.el.x(x)
} else if (coord.x !== false) {
this.el.x(coord.x)
}
}]);
return DragHandler;
}();
if (coord.y === true) {
this.el.y(y)
} else if (coord.y !== false) {
this.el.y(coord.y)
}
svg_js.extend(svg_js.Element, {
draggable: function draggable() {
var enable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
var dragHandler = this.remember('_draggable') || new DragHandler(this);
dragHandler.init(enable);
return this;
} else if (typeof c == 'object') {
// keep element within constrained box
if (c.minX != null && x < c.minX) {
x = c.minX
gx = x - this.startPoints.box.x
} else if (c.maxX != null && x > c.maxX - box.width) {
x = c.maxX - box.width
gx = x - this.startPoints.box.x
} if (c.minY != null && y < c.minY) {
y = c.minY
gy = y - this.startPoints.box.y
} else if (c.maxY != null && y > c.maxY - box.height) {
y = c.maxY - box.height
gy = y - this.startPoints.box.y
}
if (c.snapToGrid != null) {
x = x - (x % c.snapToGrid)
y = y - (y % c.snapToGrid)
gx = gx - (gx % c.snapToGrid)
gy = gy - (gy % c.snapToGrid)
}
if(this.el instanceof SVG.G)
this.el.matrix(this.startPoints.transform).transform({x:gx, y: gy}, true)
else
this.el.move(x, y)
}
});
}(SVG));
//# sourceMappingURL=svg.draggable.js.map
// so we can use it in the end-method, too
return p
}
DragHandler.prototype.end = function(e){
// final drag
var p = this.drag(e);
// fire dragend event
this.el.fire('dragend', { event: e, p: p, m: this.m, handler: this })
// unbind events
SVG.off(window, 'mousemove.drag')
SVG.off(window, 'touchmove.drag')
SVG.off(window, 'mouseup.drag')
SVG.off(window, 'touchend.drag')
}
SVG.extend(SVG.Element, {
// Make element draggable
// Constraint might be an object (as described in readme.md) or a function in the form "function (x, y)" that gets called before every move.
// The function can return a boolean or an object of the form {x, y}, to which the element will be moved. "False" skips moving, true moves to raw x, y.
draggable: function(value, constraint) {
// Check the parameters and reassign if needed
if (typeof value == 'function' || typeof value == 'object') {
constraint = value
value = true
}
var dragHandler = this.remember('_draggable') || new DragHandler(this)
// When no parameter is given, value is true
value = typeof value === 'undefined' ? true : value
if(value) dragHandler.init(constraint || {}, value)
else {
this.off('mousedown.drag')
this.off('touchstart.drag')
}
return this
}
})
}).call(this);

View file

@ -1,3 +1,4 @@
/*! @svgdotjs/svg.draggable.js v3.0.2 MIT*/;
!function(s){"use strict";function a(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var h=function(t){return t.changedTouches&&(t=t.changedTouches[0]),{x:t.clientX,y:t.clientY}},e=function(){function e(t){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,e),t.remember("_draggable",this),this.el=t,this.drag=this.drag.bind(this),this.startDrag=this.startDrag.bind(this),this.endDrag=this.endDrag.bind(this)}var t,i,n;return t=e,(i=[{key:"init",value:function(t){t?(this.el.on("mousedown.drag",this.startDrag),this.el.on("touchstart.drag",this.startDrag)):(this.el.off("mousedown.drag"),this.el.off("touchstart.drag"))}},{key:"startDrag",value:function(t){var e=!t.type.indexOf("mouse");if(!(e&&1!==(t.which||t.buttons)||this.el.dispatch("beforedrag",{event:t,handler:this}).defaultPrevented)){t.preventDefault(),t.stopPropagation(),this.init(!1),this.box=this.el.bbox(),this.lastClick=this.el.point(h(t));var i=(e?"mousemove":"touchmove")+".drag",n=(e?"mouseup":"touchcancel.drag touchend")+".drag";s.on(window,i,this.drag),s.on(window,n,this.endDrag),this.el.fire("dragstart",{event:t,handler:this,box:this.box})}}},{key:"drag",value:function(t){var e=this.box,i=this.lastClick,n=this.el.point(h(t)),a=e.x+(n.x-i.x),r=e.y+(n.y-i.y),o=new s.Box(a,r,e.w,e.h);if(!this.el.dispatch("dragmove",{event:t,handler:this,box:o}).defaultPrevented)return this.move(a,r),o}},{key:"move",value:function(t,e){"svg"===this.el.type?s.G.prototype.move.call(this.el,t,e):this.el.move(t,e)}},{key:"endDrag",value:function(t){var e=this.drag(t);this.el.fire("dragend",{event:t,handler:this,box:e}),s.off(window,"mousemove.drag"),s.off(window,"touchmove.drag"),s.off(window,"mouseup.drag"),s.off(window,"touchend.drag"),this.init(!0)}}])&&a(t.prototype,i),n&&a(t,n),e}();s.extend(s.Element,{draggable:function(){var t=!(0<arguments.length&&void 0!==arguments[0])||arguments[0];return(this.remember("_draggable")||new e(this)).init(t),this}})}(SVG);
//# sourceMappingURL=svg.draggable.min.js.map
/*! svg.draggable.js - v2.2.2 - 2019-01-08
* https://github.com/svgdotjs/svg.draggable.js
* Copyright (c) 2019 Wout Fierens; Licensed MIT */
(function(){function a(a){a.remember("_draggable",this),this.el=a}a.prototype.init=function(a,b){var c=this;this.constraint=a,this.value=b,this.el.on("mousedown.drag",function(a){c.start(a)}),this.el.on("touchstart.drag",function(a){c.start(a)})},a.prototype.transformPoint=function(a,b){a=a||window.event;var c=a.changedTouches&&a.changedTouches[0]||a;return this.p.x=c.clientX-(b||0),this.p.y=c.clientY,this.p.matrixTransform(this.m)},a.prototype.getBBox=function(){var a=this.el.bbox();return this.el instanceof SVG.Nested&&(a=this.el.rbox()),(this.el instanceof SVG.G||this.el instanceof SVG.Use||this.el instanceof SVG.Nested)&&(a.x=this.el.x(),a.y=this.el.y()),a},a.prototype.start=function(a){if("click"!=a.type&&"mousedown"!=a.type&&"mousemove"!=a.type||1==(a.which||a.buttons)){var b=this;if(this.el.fire("beforedrag",{event:a,handler:this}),!this.el.event().defaultPrevented){a.preventDefault(),a.stopPropagation(),this.parent=this.parent||this.el.parent(SVG.Nested)||this.el.parent(SVG.Doc),this.p=this.parent.node.createSVGPoint(),this.m=this.el.node.getScreenCTM().inverse();var c,d=this.getBBox();if(this.el instanceof SVG.Text)switch(c=this.el.node.getComputedTextLength(),this.el.attr("text-anchor")){case"middle":c/=2;break;case"start":c=0}this.startPoints={point:this.transformPoint(a,c),box:d,transform:this.el.transform()},SVG.on(window,"mousemove.drag",function(a){b.drag(a)}),SVG.on(window,"touchmove.drag",function(a){b.drag(a)}),SVG.on(window,"mouseup.drag",function(a){b.end(a)}),SVG.on(window,"touchend.drag",function(a){b.end(a)}),this.el.fire("dragstart",{event:a,p:this.startPoints.point,m:this.m,handler:this})}}},a.prototype.drag=function(a){var b=this.getBBox(),c=this.transformPoint(a),d=this.startPoints.box.x+c.x-this.startPoints.point.x,e=this.startPoints.box.y+c.y-this.startPoints.point.y,f=this.constraint,g=c.x-this.startPoints.point.x,h=c.y-this.startPoints.point.y;if(this.el.fire("dragmove",{event:a,p:c,m:this.m,handler:this}),this.el.event().defaultPrevented)return c;if("function"==typeof f){var i=f.call(this.el,d,e,this.m);"boolean"==typeof i&&(i={x:i,y:i}),i.x===!0?this.el.x(d):i.x!==!1&&this.el.x(i.x),i.y===!0?this.el.y(e):i.y!==!1&&this.el.y(i.y)}else"object"==typeof f&&(null!=f.minX&&d<f.minX?(d=f.minX,g=d-this.startPoints.box.x):null!=f.maxX&&d>f.maxX-b.width&&(d=f.maxX-b.width,g=d-this.startPoints.box.x),null!=f.minY&&e<f.minY?(e=f.minY,h=e-this.startPoints.box.y):null!=f.maxY&&e>f.maxY-b.height&&(e=f.maxY-b.height,h=e-this.startPoints.box.y),null!=f.snapToGrid&&(d-=d%f.snapToGrid,e-=e%f.snapToGrid,g-=g%f.snapToGrid,h-=h%f.snapToGrid),this.el instanceof SVG.G?this.el.matrix(this.startPoints.transform).transform({x:g,y:h},!0):this.el.move(d,e));return c},a.prototype.end=function(a){var b=this.drag(a);this.el.fire("dragend",{event:a,p:b,m:this.m,handler:this}),SVG.off(window,"mousemove.drag"),SVG.off(window,"touchmove.drag"),SVG.off(window,"mouseup.drag"),SVG.off(window,"touchend.drag")},SVG.extend(SVG.Element,{draggable:function(b,c){("function"==typeof b||"object"==typeof b)&&(c=b,b=!0);var d=this.remember("_draggable")||new a(this);return b="undefined"==typeof b?!0:b,b?d.init(c||{},b):(this.off("mousedown.drag"),this.off("touchstart.drag")),this}})}).call(this);

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 Ulrich-Matthias Schäfer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,511 @@
/*!
* svg.resize.js - An extension for svg.js which allows to resize elements which are selected
* @version 1.4.3
* https://github.com/svgdotjs/svg.resize.js
*
* @copyright [object Object]
* @license MIT
*/;
;(function() {
"use strict";
;(function () {
function ResizeHandler(el) {
el.remember('_resizeHandler', this);
this.el = el;
this.parameters = {};
this.lastUpdateCall = null;
this.p = el.doc().node.createSVGPoint();
}
ResizeHandler.prototype.transformPoint = function(x, y, m){
this.p.x = x - (this.offset.x - window.pageXOffset);
this.p.y = y - (this.offset.y - window.pageYOffset);
return this.p.matrixTransform(m || this.m);
};
ResizeHandler.prototype._extractPosition = function(event) {
// Extract a position from a mouse/touch event.
// Returns { x: .., y: .. }
return {
x: event.clientX != null ? event.clientX : event.touches[0].clientX,
y: event.clientY != null ? event.clientY : event.touches[0].clientY
}
};
ResizeHandler.prototype.init = function (options) {
var _this = this;
this.stop();
if (options === 'stop') {
return;
}
this.options = {};
// Merge options and defaults
for (var i in this.el.resize.defaults) {
this.options[i] = this.el.resize.defaults[i];
if (typeof options[i] !== 'undefined') {
this.options[i] = options[i];
}
}
// We listen to all these events which are specifying different edges
this.el.on('lt.resize', function(e){ _this.resize(e || window.event); }); // Left-Top
this.el.on('rt.resize', function(e){ _this.resize(e || window.event); }); // Right-Top
this.el.on('rb.resize', function(e){ _this.resize(e || window.event); }); // Right-Bottom
this.el.on('lb.resize', function(e){ _this.resize(e || window.event); }); // Left-Bottom
this.el.on('t.resize', function(e){ _this.resize(e || window.event); }); // Top
this.el.on('r.resize', function(e){ _this.resize(e || window.event); }); // Right
this.el.on('b.resize', function(e){ _this.resize(e || window.event); }); // Bottom
this.el.on('l.resize', function(e){ _this.resize(e || window.event); }); // Left
this.el.on('rot.resize', function(e){ _this.resize(e || window.event); }); // Rotation
this.el.on('point.resize', function(e){ _this.resize(e || window.event); }); // Point-Moving
// This call ensures, that the plugin reacts to a change of snapToGrid immediately
this.update();
};
ResizeHandler.prototype.stop = function(){
this.el.off('lt.resize');
this.el.off('rt.resize');
this.el.off('rb.resize');
this.el.off('lb.resize');
this.el.off('t.resize');
this.el.off('r.resize');
this.el.off('b.resize');
this.el.off('l.resize');
this.el.off('rot.resize');
this.el.off('point.resize');
return this;
};
ResizeHandler.prototype.resize = function (event) {
var _this = this;
this.m = this.el.node.getScreenCTM().inverse();
this.offset = { x: window.pageXOffset, y: window.pageYOffset };
var txPt = this._extractPosition(event.detail.event);
this.parameters = {
type: this.el.type, // the type of element
p: this.transformPoint(txPt.x, txPt.y),
x: event.detail.x, // x-position of the mouse when resizing started
y: event.detail.y, // y-position of the mouse when resizing started
box: this.el.bbox(), // The bounding-box of the element
rotation: this.el.transform().rotation // The current rotation of the element
};
this.resizeLimits = this.options.resizeLimits || this.resize.defaults.resizeLimits;
// Add font-size parameter if the element type is text
if (this.el.type === "text") {
this.parameters.fontSize = this.el.attr()["font-size"];
}
// the i-param in the event holds the index of the point which is moved, when using `deepSelect`
if (event.detail.i !== undefined) {
// get the point array
var array = this.el.array().valueOf();
// Save the index and the point which is moved
this.parameters.i = event.detail.i;
this.parameters.pointCoords = [array[event.detail.i][0], array[event.detail.i][1]];
}
this._resizeLeft = function (snap, resizeFont, checkAspectRatio, checkAspectRatioReverse, updateOnlyChanges) {
if (this.parameters.box.width - snap[0] >= this.resizeLimits.width) {
if (checkAspectRatio) {
snap = this.checkAspectRatio(snap, checkAspectRatioReverse);
}
if (this.parameters.type === "text") {
if (resizeFont) {
this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y);
this.el.attr("font-size", this.parameters.fontSize - snap[0]);
}
return;
}
this.el.width(this.parameters.box.width - snap[0]);
if (updateOnlyChanges) {
this.el.x(this.parameters.box.x + snap[0]);
} else {
this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y);
}
}
};
this._resizeRight = function (snap, resizeFont, checkAspectRatio, checkAspectRatioReverse) {
if (this.parameters.box.width + snap[0] >= this.resizeLimits.width) {
if (checkAspectRatio) {
snap = this.checkAspectRatio(snap, checkAspectRatioReverse);
}
if (this.parameters.type === "text") {
if (resizeFont) {
this.el.move(this.parameters.box.x - snap[0], this.parameters.box.y);
this.el.attr("font-size", this.parameters.fontSize + snap[0]);
}
return;
}
this.el.x(this.parameters.box.x).width(this.parameters.box.width + snap[0]);
}
};
this._resizeTop = function (snap, checkAspectRatio, checkAspectRatioReverse, updateOnlyChanges) {
if (this.parameters.box.height - snap[1] >= this.resizeLimits.height) {
if (checkAspectRatio) {
snap = this.checkAspectRatio(snap, checkAspectRatioReverse);
}
// Disable the font-resizing if it is not from the corner of bounding-box
if (this.parameters.type === "text") {
return;
}
this.el.height(this.parameters.box.height - snap[1]);
if (updateOnlyChanges) {
this.el.y(this.parameters.box.y + snap[1])
} else {
this.el.move(this.parameters.box.x, this.parameters.box.y + snap[1]);
}
}
};
this._resizeBottom = function (snap, checkAspectRatio, checkAspectRatioReverse) {
if (this.parameters.box.height + snap[1] >= this.resizeLimits.height) {
if (checkAspectRatio) {
snap = this.checkAspectRatio(snap, checkAspectRatioReverse);
}
if (this.parameters.type === "text") {
return;
}
this.el.y(this.parameters.box.y).height(this.parameters.box.height + snap[1]);
}
};
// Lets check which edge of the bounding-box was clicked and resize the this.el according to this
switch (event.type) {
// Left-Top-Edge
case 'lt':
// We build a calculating function for every case which gives us the new position of the this.el
this.calc = function (diffX, diffY) {
// The procedure is always the same
// First we snap the edge to the given grid (snapping to 1px grid is normal resizing)
var snap = this.snapToGrid(diffX, diffY);
this._resizeTop(snap, true, false, true);
this._resizeLeft(snap, true, true, false, true);
};
break;
// Right-Top
case 'rt':
// s.a.
this.calc = function (diffX, diffY) {
var snap = this.snapToGrid(diffX, diffY, 1 << 1);
this._resizeTop(snap, true, true, true);
this._resizeRight(snap, true, true, true);
};
break;
// Right-Bottom
case 'rb':
// s.a.
this.calc = function (diffX, diffY) {
var snap = this.snapToGrid(diffX, diffY, 0);
this._resizeBottom(snap, true);
this._resizeRight(snap, true, true);
};
break;
// Left-Bottom
case 'lb':
// s.a.
this.calc = function (diffX, diffY) {
var snap = this.snapToGrid(diffX, diffY, 1);
this._resizeBottom(snap, true, true);
this._resizeLeft(snap, true, true, true, true);
};
break;
// Top
case 't':
// s.a.
this.calc = function (diffX, diffY) {
var snap = this.snapToGrid(diffX, diffY, 1 << 1);
this._resizeTop(snap);
};
break;
// Right
case 'r':
// s.a.
this.calc = function (diffX, diffY) {
var snap = this.snapToGrid(diffX, diffY, 0);
this._resizeRight(snap);
};
break;
// Bottom
case 'b':
// s.a.
this.calc = function (diffX, diffY) {
var snap = this.snapToGrid(diffX, diffY, 0);
this._resizeBottom(snap);
};
break;
// Left
case 'l':
// s.a.
this.calc = function (diffX, diffY) {
var snap = this.snapToGrid(diffX, diffY, 1);
this._resizeLeft(snap);
};
break;
// Rotation
case 'rot':
// s.a.
this.calc = function (diffX, diffY) {
// yes this is kinda stupid but we need the mouse coords back...
var current = {x: diffX + this.parameters.p.x, y: diffY + this.parameters.p.y};
// start minus middle
var sAngle = Math.atan2((this.parameters.p.y - this.parameters.box.y - this.parameters.box.height / 2), (this.parameters.p.x - this.parameters.box.x - this.parameters.box.width / 2));
// end minus middle
var pAngle = Math.atan2((current.y - this.parameters.box.y - this.parameters.box.height / 2), (current.x - this.parameters.box.x - this.parameters.box.width / 2));
var angle = this.parameters.rotation + (pAngle - sAngle) * 180 / Math.PI + this.options.snapToAngle / 2;
// We have to move the element to the center of the box first and change the rotation afterwards
// because rotation always works around a rotation-center, which is changed when moving the element
// We also set the new rotation center to the center of the box.
this.el.center(this.parameters.box.cx, this.parameters.box.cy).rotate(angle - (angle % this.options.snapToAngle), this.parameters.box.cx, this.parameters.box.cy);
};
break;
// Moving one single Point (needed when an element is deepSelected which means you can move every single point of the object)
case 'point':
this.calc = function (diffX, diffY) {
// Snapping the point to the grid
var snap = this.snapToGrid(diffX, diffY, this.parameters.pointCoords[0], this.parameters.pointCoords[1]);
// Get the point array
var array = this.el.array().valueOf();
// Changing the moved point in the array
array[this.parameters.i][0] = this.parameters.pointCoords[0] + snap[0];
array[this.parameters.i][1] = this.parameters.pointCoords[1] + snap[1];
// And plot the new this.el
this.el.plot(array);
};
}
this.el.fire('resizestart', {dx: this.parameters.x, dy: this.parameters.y, event: event});
// When resizing started, we have to register events for...
// Touches.
SVG.on(window, 'touchmove.resize', function(e) {
_this.update(e || window.event);
});
SVG.on(window, 'touchend.resize', function() {
_this.done();
});
// Mouse.
SVG.on(window, 'mousemove.resize', function (e) {
_this.update(e || window.event);
});
SVG.on(window, 'mouseup.resize', function () {
_this.done();
});
};
// The update-function redraws the element every time the mouse is moving
ResizeHandler.prototype.update = function (event) {
if (!event) {
if (this.lastUpdateCall) {
this.calc(this.lastUpdateCall[0], this.lastUpdateCall[1]);
}
return;
}
// Calculate the difference between the mouseposition at start and now
var txPt = this._extractPosition(event);
var p = this.transformPoint(txPt.x, txPt.y);
var diffX = p.x - this.parameters.p.x,
diffY = p.y - this.parameters.p.y;
this.lastUpdateCall = [diffX, diffY];
// Calculate the new position and height / width of the element
this.calc(diffX, diffY);
// Emit an event to say we have changed.
this.el.fire('resizing', {dx: diffX, dy: diffY, event: event});
};
// Is called on mouseup.
// Removes the update-function from the mousemove event
ResizeHandler.prototype.done = function () {
this.lastUpdateCall = null;
SVG.off(window, 'mousemove.resize');
SVG.off(window, 'mouseup.resize');
SVG.off(window, 'touchmove.resize');
SVG.off(window, 'touchend.resize');
this.el.fire('resizedone');
};
// The flag is used to determine whether the resizing is used with a left-Point (first bit) and top-point (second bit)
// In this cases the temp-values are calculated differently
ResizeHandler.prototype.snapToGrid = function (diffX, diffY, flag, pointCoordsY) {
var temp;
// If `pointCoordsY` is given, a single Point has to be snapped (deepSelect). That's why we need a different temp-value
if (typeof pointCoordsY !== 'undefined') {
// Note that flag = pointCoordsX in this case
temp = [(flag + diffX) % this.options.snapToGrid, (pointCoordsY + diffY) % this.options.snapToGrid];
} else {
// We check if the flag is set and if not we set a default-value (both bits set - which means upper-left-edge)
flag = flag == null ? 1 | 1 << 1 : flag;
temp = [(this.parameters.box.x + diffX + (flag & 1 ? 0 : this.parameters.box.width)) % this.options.snapToGrid, (this.parameters.box.y + diffY + (flag & (1 << 1) ? 0 : this.parameters.box.height)) % this.options.snapToGrid];
}
if(diffX < 0) {
temp[0] -= this.options.snapToGrid;
}
if(diffY < 0) {
temp[1] -= this.options.snapToGrid;
}
diffX -= (Math.abs(temp[0]) < this.options.snapToGrid / 2 ?
temp[0] :
temp[0] - (diffX < 0 ? -this.options.snapToGrid : this.options.snapToGrid));
diffY -= (Math.abs(temp[1]) < this.options.snapToGrid / 2 ?
temp[1] :
temp[1] - (diffY < 0 ? -this.options.snapToGrid : this.options.snapToGrid));
return this.constraintToBox(diffX, diffY, flag, pointCoordsY);
};
// keep element within constrained box
ResizeHandler.prototype.constraintToBox = function (diffX, diffY, flag, pointCoordsY) {
//return [diffX, diffY]
var c = this.options.constraint || {};
var orgX, orgY;
if (typeof pointCoordsY !== 'undefined') {
orgX = flag;
orgY = pointCoordsY;
} else {
orgX = this.parameters.box.x + (flag & 1 ? 0 : this.parameters.box.width);
orgY = this.parameters.box.y + (flag & (1<<1) ? 0 : this.parameters.box.height);
}
if (typeof c.minX !== 'undefined' && orgX + diffX < c.minX) {
diffX = c.minX - orgX;
}
if (typeof c.maxX !== 'undefined' && orgX + diffX > c.maxX) {
diffX = c.maxX - orgX;
}
if (typeof c.minY !== 'undefined' && orgY + diffY < c.minY) {
diffY = c.minY - orgY;
}
if (typeof c.maxY !== 'undefined' && orgY + diffY > c.maxY) {
diffY = c.maxY - orgY;
}
return [diffX, diffY];
};
ResizeHandler.prototype.checkAspectRatio = function (snap, isReverse) {
if (!this.options.saveAspectRatio) {
return snap;
}
var updatedSnap = snap.slice();
var aspectRatio = this.parameters.box.width / this.parameters.box.height;
var newW = this.parameters.box.width + snap[0];
var newH = this.parameters.box.height - snap[1];
var newAspectRatio = newW / newH;
if (newAspectRatio < aspectRatio) {
// Height is too big. Adapt it
updatedSnap[1] = newW / aspectRatio - this.parameters.box.height;
isReverse && (updatedSnap[1] = -updatedSnap[1]);
} else if (newAspectRatio > aspectRatio) {
// Width is too big. Adapt it
updatedSnap[0] = this.parameters.box.width - newH * aspectRatio;
isReverse && (updatedSnap[0] = -updatedSnap[0]);
}
return updatedSnap;
};
SVG.extend(SVG.Element, {
// Resize element with mouse
resize: function (options) {
(this.remember('_resizeHandler') || new ResizeHandler(this)).init(options || {});
return this;
}
});
SVG.Element.prototype.resize.defaults = {
snapToAngle: 0.1, // Specifies the speed the rotation is happening when moving the mouse
snapToGrid: 1, // Snaps to a grid of `snapToGrid` Pixels
constraint: {}, // keep element within constrained box
resizeLimits: { width: 0, height: 0 }, // rect limit size on resize
saveAspectRatio: false // Save aspect ratio when resizing using lt, rt, rb or lb points
};
}).call(this);
}());

File diff suppressed because one or more lines are too long

View file

@ -422,4 +422,4 @@ SVG.Element.prototype.selectize.defaults = {
pointFill: "#000", // Point fill color
pointStroke: { width: 1, color: "#000" } // Point stroke properties
};
}());
}());

View file

@ -13,7 +13,7 @@ $(function(){
// Setup map
// ------------------------------------------
svg = SVG("#map").size("100%", "700").viewbox(0, 0, 1000, 700);
svg = SVG('map');
// Initialize events
@ -23,11 +23,11 @@ $(function(){
$("#button-save").click(function() {
saveMap();
editMode(false);
drawMap();
fetchData(drawMap);
});
$("#button-cancel").click(function() {
editMode(false);
drawMap();
fetchData(drawMap);
});
// Initialize background image uploader
@ -92,14 +92,23 @@ function editMode(enable){
editModeEnabled = enable;
if (editModeEnabled) {
$(".edit-mode").show();
$(".view-mode").hide();
$("#map").css("border-color", "#6eb16e");
$('.edit-mode').show();
$('.view-mode').hide();
$('#map').css('border-color', '#6eb16e');
svg.select('.draggable').draggable(true);
//svg.select('.resizable').on('click', selectEvent, false);
svg.select('.resizable').selectize({
points: ['rt', 'lb', 'rb'], // Add selection points on the corners
rotationPoint: false
}).resize()
} else {
$(".room").selectize(false)
$(".edit-mode").hide();
$(".view-mode").show();
$("#map").css("border-color", "");
$('.edit-mode').hide();
$('.view-mode').show();
$('#map').css('border-color', '');
svg.select('.draggable').draggable(false);
svg.select('resizable').selectize(false);
}
}
@ -109,9 +118,12 @@ function beforeDragEvent(e) {
}
}
function selectEntity(e) {
if (editModeEnabled == false) {
e.target.selectize();
function selectEvent(e) {
if (editModeEnabled == true) {
e.target.selectize({
points: ['rt', 'lb', 'rb'], // Add selection points on the corners
rotationPoint: false
}).resize();
}
}
@ -121,11 +133,11 @@ function selectEntity(e) {
function drawMap() {
// Reset map
//svg.clear();
svg.clear();
// Background
if (svg.find(".bg-image").length <= 0) {
if (svg.select(".bg-image").length() <= 0) {
var bgImage = svg.image("?bgimage").addClass("bg-image")
.x(0)
.y(0)
@ -137,21 +149,25 @@ function drawMap() {
if (data.rooms != null) {
$.each(data.rooms, function(i, room) {
svg.find("#room-" + room.id).remove();
svg.select("#room-" + room.id).remove();
var group = svg.group();
group.text(room.name).move(5, 5).fill('#999');
group.rect(room.map.width, room.map.height).selectize();
var rect = group.rect(room.map.width, room.map.height);
rect.fill('none').stroke({
color: '#000',
opacity: 0.6,
width: 3
});
rect.addClass("resizable");
group.addClass("room")
.attr("id", "room-" + room.id)
.attr("room-id", room.id)
.x(room.map.x)
.y(room.map.y);
group.draggable().on('beforedrag', beforeDragEvent);
//group.on('mousedown', selectEntity, false);
.y(room.map.y)
.addClass("draggable");
});
}
@ -159,7 +175,7 @@ function drawMap() {
if (data.sensors != null) {
$.each(data.sensors, function(i, sensor) {
svg.find("#sensor-" + sensor.id).remove();
svg.select("#sensor-" + sensor.id).remove();
var group = svg.group();
group.element('title').words(sensor.name);
@ -171,8 +187,8 @@ function drawMap() {
.attr("id", "sensor-" + sensor.id)
.attr("sensor-id", sensor.id)
.x(sensor.map.x)
.y(sensor.map.y);
group.draggable().on('beforedrag', beforeDragEvent);
.y(sensor.map.y)
.addClass("draggable");
});
}
@ -180,7 +196,7 @@ function drawMap() {
if (data.events != null) {
$.each(data.events, function(i, event) {
svg.find("#event-" + event.id).remove();
svg.select("#event-" + event.id).remove();
var group = svg.group();
group.element('title').words(event.name);
@ -194,8 +210,8 @@ function drawMap() {
.attr("id", "event-" + event.id)
.attr("event-id", event.id)
.x(event.map.x)
.y(event.map.y);
group.draggable().on('beforedrag', beforeDragEvent);
.y(event.map.y)
.addClass("draggable");
});
}
}
@ -227,27 +243,35 @@ async function fetchData(callback) {
}
function saveMap(){
svg.find(".room").each(function(){
svg.select(".room").each(function(){
saveDevice(this, "room", "room-id");
});
svg.find(".sensor").each(function(){
svg.select(".sensor").each(function(){
saveDevice(this, "sensor", "sensor-id");
});
svg.find(".event").each(function(){
svg.select(".event").each(function(){
saveDevice(this, "event", "event-id");
});
}
function saveDevice(element, type, id){
function saveDevice(element, type, id) {
var data = {
action: "save",
id: element.attr(id),
type: type,
x: element.x(),
y: element.y()
};
var resizable = element.select(".resizable");
if (resizable.length() > 0) {
data.width = resizable.get(0).width();
data.height = resizable.get(0).height();
}
$.ajax({
async: false,
dataType: "json",
url: "/api/map?",
data: {
action: "save",
id: element.attr(id),
type: type,
x: element.x(),
y: element.y()
},
data: data
});
}

View file

@ -13,7 +13,7 @@
</style>
<div class="col-sm-9 col-sm-offset-1 col-md-10 col-md-offset-1">
<svg id="map"></svg>
<svg id="map" width="100%" height="700" viewBox="0, 0, 1000, 700"></svg>
</div>
<div class="col-sm-1 col-md-1">
@ -43,11 +43,12 @@
</div>
<link href="css/jquery.filer.css" rel="stylesheet">
<link href="css/svg.select.min.js" rel="stylesheet">
<link href="css/svg.select.min.css" rel="stylesheet">
<script src="js/lib/jquery.filer.min.js"></script>
<script src="js/lib/svg.min.js"></script>
<script src="js/lib/svg.select.min.js"></script>
<script src="js/lib/svg.resize.min.js"></script>
<script src="js/lib/svg.draggable.min.js"></script>
<script src="js/map.js"></script>

View file

@ -4,6 +4,7 @@ import se.hal.HalContext;
import se.hal.intf.HalAbstractDevice;
import se.hal.intf.HalApiEndpoint;
import se.hal.struct.Event;
import se.hal.struct.Room;
import se.hal.struct.Sensor;
import zutil.db.DBConnection;
import zutil.log.LogUtil;
@ -35,20 +36,38 @@ public class MapApiEndpoint extends HalApiEndpoint {
if ("save".equals(request.get("action"))) {
int id = Integer.parseInt(request.get("id"));
HalAbstractDevice device = null;
logger.info("Saving Sensor coordinates.");
logger.info("Saving map coordinates.");
if ("sensor".equals(request.get("type")))
device = Sensor.getSensor(db, id);
else if ("event".equals(request.get("type")))
device = Event.getEvent(db, id);
switch (request.get("type")) {
case "room":
Room room = Room.getRoom(db, id);
room.setMapCoordinates(
Float.parseFloat(request.get("x")),
Float.parseFloat(request.get("y")),
Float.parseFloat(request.get("width")),
Float.parseFloat(request.get("height")));
room.save(db);
break;
device.setMapCoordinates(
Float.parseFloat(request.get("x")),
Float.parseFloat(request.get("y")));
device.save(db);
case "sensor":
Sensor sensor = Sensor.getSensor(db, id);
sensor.setMapCoordinates(
Float.parseFloat(request.get("x")),
Float.parseFloat(request.get("y")));
sensor.save(db);
break;
case "event":
Event event = Event.getEvent(db, id);
event.setMapCoordinates(
Float.parseFloat(request.get("x")),
Float.parseFloat(request.get("y")));
event.save(db);
break;
}
}
return root;
}
}