Upgraded svg.js library to version 3

This commit is contained in:
Ziver Koc 2023-01-10 00:53:30 +01:00
parent d8a1b66738
commit fb7f43ed23
17 changed files with 7968 additions and 5917 deletions

View file

@ -30,6 +30,7 @@ subprojects {
java {
srcDirs 'src'
}
// We do not want the resource folder to be included in the jar file
//resources {
// srcDir 'resource'
//}

View file

@ -0,0 +1,64 @@
.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{
cursor: nw-resize;
}
.svg_select_points_rt{
cursor: ne-resize;
}
.svg_select_points_rb{
cursor: se-resize;
}
.svg_select_points_lb{
cursor: sw-resize;
}
.svg_select_points_t{
cursor: n-resize;
}
.svg_select_points_r{
cursor: e-resize;
}
.svg_select_points_b{
cursor: s-resize;
}
.svg_select_points_l{
cursor: w-resize;
}
.svg_select_points_rot{
stroke-width:1;
stroke:black;
fill: #F9FFED;
}
.svg_select_points_point{
cursor: move;
}
.svg_select_boundingRect{
stroke-width:1;
fill:gray;
stroke-dasharray:10 10;
stroke:black;
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

@ -0,0 +1 @@
.svg_select_points_lt{cursor:nw-resize}.svg_select_points_rt{cursor:ne-resize}.svg_select_points_rb{cursor:se-resize}.svg_select_points_lb{cursor:sw-resize}.svg_select_points_t{cursor:n-resize}.svg_select_points_r{cursor:e-resize}.svg_select_points_b{cursor:s-resize}.svg_select_points_l{cursor:w-resize}.svg_select_points_rot{stroke-width:1;stroke:#000;fill:#f9ffed}.svg_select_points_point{cursor:move}.svg_select_boundingRect{stroke-width:1;fill:gray;stroke-dasharray:10 10;stroke:#000;stroke-opacity:.8;fill-opacity:.1;pointer-events:none}

View file

@ -2,6 +2,8 @@
// Autostart
// --------------------------------------------------------
"use strict";
$(function(){
$(".toggle-switch").bootstrapSwitch({inverse: true, size: "mini"});

View file

@ -1,221 +1,177 @@
/*! svg.draggable.js - v2.2.0 - 2016-05-21
* https://github.com/wout/svg.draggable.js
* Copyright (c) 2016 Wout Fierens; Licensed MIT */
;(function() {
/*!
* @svgdotjs/svg.draggable.js - An extension for svg.js which allows to drag elements with your mouse
* @version 3.0.2
* 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';
// creates handler, saves it
function DragHandler(el){
el.remember('_draggable', this)
this.el = el
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
// 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 _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);
}
}
// 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.pageX - (offset || 0)
this.p.y = touches.pageY
return this.p.matrixTransform(this.m)
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
// 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()
var getCoordsFromEvent = function getCoordsFromEvent(ev) {
if (ev.changedTouches) {
ev = ev.changedTouches[0];
}
return box
}
return {
x: ev.clientX,
y: ev.clientY
};
}; // Creates handler, saves it
// start dragging
DragHandler.prototype.start = function(e){
// check for left button
if(e.type == 'click'|| e.type == 'mousedown' || e.type == 'mousemove'){
if((e.which || e.buttons) != 1){
return
}
}
var _this = this
var DragHandler =
/*#__PURE__*/
function () {
function DragHandler(el) {
_classCallCheck(this, DragHandler);
// fire beforedrag event
this.el.fire('beforedrag', { event: e, handler: this })
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
// 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
}
// 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})
// prevent browser drag behavior
e.preventDefault()
// prevent propagation to a parent that might also have dragging enabled
e.stopPropagation();
}
// 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
var event = new CustomEvent('dragmove', {
detail: {
event: e
, p: p
, m: this.m
, handler: this
_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');
}
, cancelable: true
})
this.el.fire(event)
if(event.defaultPrevented) return p
} // Start dragging
// move the element to its new position, if possible by constraint
if (typeof c == 'function') {
}, {
key: "startDrag",
value: function startDrag(ev) {
var isMouse = !ev.type.indexOf('mouse'); // Check for left button
var coord = c.call(this.el, x, y, this.m)
if (isMouse && (ev.which || ev.buttons) !== 1) {
return;
} // Fire beforedrag event
// bool, just show us if movement is allowed or not
if (typeof coord == 'boolean') {
coord = {
x: coord,
y: coord
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;
}
}, {
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);
}
}
}, {
key: "endDrag",
value: function endDrag(ev) {
// final drag
var box = this.drag(ev); // fire dragend event
// 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)
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 (coord.y === true) {
this.el.y(y)
} else if (coord.y !== false) {
this.el.y(coord.y)
}
return DragHandler;
}();
} else if (typeof c == 'object') {
// keep element within constrained box
if (c.minX != null && x < c.minX)
x = c.minX
else if (c.maxX != null && x > c.maxX - box.width){
x = c.maxX - box.width
}if (c.minY != null && y < c.minY)
y = c.minY
else if (c.maxY != null && y > c.maxY - box.height)
y = c.maxY - box.height
this.el.move(x, 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;
}
// 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);
}(SVG));
//# sourceMappingURL=svg.draggable.js.map

View file

@ -1,4 +1,3 @@
/*! svg.draggable.js - v2.2.0 - 2016-05-21
* https://github.com/wout/svg.draggable.js
* Copyright (c) 2016 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.pageX-(b||0),this.p.y=c.pageY,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;this.el.fire("beforedrag",{event:a,handler:this}),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},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.preventDefault(),a.stopPropagation()}},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=new CustomEvent("dragmove",{detail:{event:a,p:c,m:this.m,handler:this},cancelable:!0});if(this.el.fire(g),g.defaultPrevented)return c;if("function"==typeof f){var h=f.call(this.el,d,e,this.m);"boolean"==typeof h&&(h={x:h,y:h}),h.x===!0?this.el.x(d):h.x!==!1&&this.el.x(h.x),h.y===!0?this.el.y(e):h.y!==!1&&this.el.y(h.y)}else"object"==typeof f&&(null!=f.minX&&d<f.minX?d=f.minX:null!=f.maxX&&d>f.maxX-b.width&&(d=f.maxX-b.width),null!=f.minY&&e<f.minY?e=f.minY:null!=f.maxY&&e>f.maxY-b.height&&(e=f.maxY-b.height),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);
/*! @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

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) 2014 Fuzzy
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,425 @@
/*!
* svg.select.js - An extension of svg.js which allows to select elements with mouse
* @version 3.0.1
* https://github.com/svgdotjs/svg.select.js
*
* @copyright Ulrich-Matthias Schäfer
* @license MIT
*/;
;(function() {
"use strict";
function SelectHandler(el) {
this.el = el;
el.remember('_selectHandler', this);
this.pointSelection = {isSelected: false};
this.rectSelection = {isSelected: false};
// helper list with position settings of each type of point
this.pointsList = {
lt: [ 0, 0 ],
rt: [ 'width', 0 ],
rb: [ 'width', 'height' ],
lb: [ 0, 'height' ],
t: [ 'width', 0 ],
r: [ 'width', 'height' ],
b: [ 'width', 'height' ],
l: [ 0, 'height' ]
};
// helper function to get point coordinates based on settings above and an object (bbox in our case)
this.pointCoord = function (setting, object, isPointCentered) {
var coord = typeof setting !== 'string' ? setting : object[setting];
// Top, bottom, right and left points are placed in the center of element width/height
return isPointCentered ? coord / 2 : coord
}
this.pointCoords = function (point, object) {
var settings = this.pointsList[point];
return {
x: this.pointCoord(settings[0], object, (point === 't' || point === 'b')),
y: this.pointCoord(settings[1], object, (point === 'r' || point === 'l'))
}
}
}
SelectHandler.prototype.init = function (value, options) {
var bbox = this.el.bbox();
this.options = {};
// store defaults list of points in order to verify users config
var points = this.el.selectize.defaults.points;
// Merging the defaults and the options-object together
for (var i in this.el.selectize.defaults) {
this.options[i] = this.el.selectize.defaults[i];
if (options[i] !== undefined) {
this.options[i] = options[i];
}
}
// prepare & validate list of points to be added (or excluded)
var pointsLists = ['points', 'pointsExclude'];
for (var i in pointsLists) {
var option = this.options[pointsLists[i]];
if (typeof option === 'string') {
if (option.length > 0) {
// if set as comma separated string list => convert it into an array
option = option.split(/\s*,\s*/i);
} else {
option = [];
}
} else if (typeof option === 'boolean' && pointsLists[i] === 'points') {
// this is not needed, but let's have it for legacy support
option = option ? points : [];
}
this.options[pointsLists[i]] = option;
}
// intersect correct all points options with users config (exclude unwanted points)
// ES5 -> NO arrow functions nor Array.includes()
this.options.points = [ points, this.options.points ].reduce(
function (a, b) {
return a.filter(
function (c) {
return b.indexOf(c) > -1;
}
)
}
);
// exclude pointsExclude, if wanted
this.options.points = [ this.options.points, this.options.pointsExclude ].reduce(
function (a, b) {
return a.filter(
function (c) {
return b.indexOf(c) < 0;
}
)
}
);
this.parent = this.el.parent();
this.nested = (this.nested || this.parent.group());
this.nested.matrix(new SVG.Matrix(this.el).translate(bbox.x, bbox.y));
// When deepSelect is enabled and the element is a line/polyline/polygon, draw only points for moving
if (this.options.deepSelect && ['line', 'polyline', 'polygon'].indexOf(this.el.type) !== -1) {
this.selectPoints(value);
} else {
this.selectRect(value);
}
this.observe();
this.cleanup();
};
SelectHandler.prototype.selectPoints = function (value) {
this.pointSelection.isSelected = value;
// When set is already there we dont have to create one
if (this.pointSelection.set) {
return this;
}
// Create our set of elements
this.pointSelection.set = this.parent.set();
// draw the points and mark the element as selected
this.drawPoints();
return this;
};
// create the point-array which contains the 2 points of a line or simply the points-array of polyline/polygon
SelectHandler.prototype.getPointArray = function () {
var bbox = this.el.bbox();
return this.el.array().valueOf().map(function (el) {
return [el[0] - bbox.x, el[1] - bbox.y];
});
};
// Draws a points
SelectHandler.prototype.drawPoints = function () {
var _this = this, array = this.getPointArray();
// go through the array of points
for (var i = 0, len = array.length; i < len; ++i) {
var curriedEvent = (function (k) {
return function (ev) {
ev = ev || window.event;
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
ev.stopPropagation();
var x = ev.pageX || ev.touches[0].pageX;
var y = ev.pageY || ev.touches[0].pageY;
_this.el.fire('point', {x: x, y: y, i: k, event: ev});
};
})(i);
// add every point to the set
// add css-classes and a touchstart-event which fires our event for moving points
var point = this.drawPoint(array[i][0], array[i][1])
.addClass(this.options.classPoints)
.addClass(this.options.classPoints + '_point')
.on('touchstart', curriedEvent)
.on('mousedown', curriedEvent)
this.pointSelection.set.add(point);
}
};
// The function to draw single point
SelectHandler.prototype.drawPoint = function (cx, cy) {
var pointType = this.options.pointType;
switch (pointType) {
case 'circle':
return this.drawCircle(cx, cy);
case 'rect':
return this.drawRect(cx, cy);
default:
if (typeof pointType === 'function') {
return pointType.call(this, cx, cy);
}
throw new Error('Unknown ' + pointType + ' point type!');
}
};
// The function to draw the circle point
SelectHandler.prototype.drawCircle = function (cx, cy) {
return this.nested.circle(this.options.pointSize)
.stroke(this.options.pointStroke)
.fill(this.options.pointFill)
.center(cx, cy);
};
// The function to draw the rect point
SelectHandler.prototype.drawRect = function (cx, cy) {
return this.nested.rect(this.options.pointSize, this.options.pointSize)
.stroke(this.options.pointStroke)
.fill(this.options.pointFill)
.center(cx, cy);
};
// every time a point is moved, we have to update the positions of our point
SelectHandler.prototype.updatePointSelection = function () {
var array = this.getPointArray();
this.pointSelection.set.each(function (i) {
if (this.cx() === array[i][0] && this.cy() === array[i][1]) {
return;
}
this.center(array[i][0], array[i][1]);
});
};
SelectHandler.prototype.updateRectSelection = function () {
var _this = this, bbox = this.el.bbox();
this.rectSelection.set.get(0).attr({
width: bbox.width,
height: bbox.height
});
// set.get(1) is always in the upper left corner. no need to move it
if (this.options.points.length) {
this.options.points.map(function (point, index) {
var coords = _this.pointCoords(point, bbox);
_this.rectSelection.set.get(index + 1).center(coords.x, coords.y);
});
}
if (this.options.rotationPoint) {
var length = this.rectSelection.set.length();
this.rectSelection.set.get(length - 1).center(bbox.width / 2, 20);
}
};
SelectHandler.prototype.selectRect = function (value) {
var _this = this, bbox = this.el.bbox();
this.rectSelection.isSelected = value;
// when set is already p
this.rectSelection.set = this.rectSelection.set || this.parent.set();
// helperFunction to create a mouse-down function which triggers the event specified in `eventName`
function getMoseDownFunc(eventName) {
return function (ev) {
ev = ev || window.event;
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
ev.stopPropagation();
var x = ev.pageX || ev.touches[0].pageX;
var y = ev.pageY || ev.touches[0].pageY;
_this.el.fire(eventName, {x: x, y: y, event: ev});
};
}
// create the selection-rectangle and add the css-class
if (!this.rectSelection.set.get(0)) {
this.rectSelection.set.add(this.nested.rect(bbox.width, bbox.height).addClass(this.options.classRect));
}
// Draw Points at the edges, if enabled
if (this.options.points.length && this.rectSelection.set.length() < 2) {
var ename ="touchstart", mname = "mousedown";
this.options.points.map(function (point, index) {
var coords = _this.pointCoords(point, bbox);
var pointElement = _this.drawPoint(coords.x, coords.y)
.attr('class', _this.options.classPoints + '_' + point)
.on(mname, getMoseDownFunc(point))
.on(ename, getMoseDownFunc(point));
_this.rectSelection.set.add(pointElement);
});
this.rectSelection.set.each(function () {
this.addClass(_this.options.classPoints);
});
}
// draw rotationPint, if enabled
if (this.options.rotationPoint && ((this.options.points && !this.rectSelection.set.get(9)) || (!this.options.points && !this.rectSelection.set.get(1)))) {
var curriedEvent = function (ev) {
ev = ev || window.event;
ev.preventDefault ? ev.preventDefault() : ev.returnValue = false;
ev.stopPropagation();
var x = ev.pageX || ev.touches[0].pageX;
var y = ev.pageY || ev.touches[0].pageY;
_this.el.fire('rot', {x: x, y: y, event: ev});
};
var pointElement = this.drawPoint(bbox.width / 2, 20)
.attr('class', this.options.classPoints + '_rot')
.on("touchstart", curriedEvent)
.on("mousedown", curriedEvent);
this.rectSelection.set.add(pointElement);
}
};
SelectHandler.prototype.handler = function () {
var bbox = this.el.bbox();
this.nested.matrix(new SVG.Matrix(this.el).translate(bbox.x, bbox.y));
if (this.rectSelection.isSelected) {
this.updateRectSelection();
}
if (this.pointSelection.isSelected) {
this.updatePointSelection();
}
};
SelectHandler.prototype.observe = function () {
var _this = this;
if (MutationObserver) {
if (this.rectSelection.isSelected || this.pointSelection.isSelected) {
this.observerInst = this.observerInst || new MutationObserver(function () {
_this.handler();
});
this.observerInst.observe(this.el.node, {attributes: true});
} else {
try {
this.observerInst.disconnect();
delete this.observerInst;
} catch (e) {
}
}
} else {
this.el.off('DOMAttrModified.select');
if (this.rectSelection.isSelected || this.pointSelection.isSelected) {
this.el.on('DOMAttrModified.select', function () {
_this.handler();
});
}
}
};
SelectHandler.prototype.cleanup = function () {
//var _this = this;
if (!this.rectSelection.isSelected && this.rectSelection.set) {
// stop watching the element, remove the selection
this.rectSelection.set.each(function () {
this.remove();
});
this.rectSelection.set.clear();
delete this.rectSelection.set;
}
if (!this.pointSelection.isSelected && this.pointSelection.set) {
// Remove all points, clear the set, stop watching the element
this.pointSelection.set.each(function () {
this.remove();
});
this.pointSelection.set.clear();
delete this.pointSelection.set;
}
if (!this.pointSelection.isSelected && !this.rectSelection.isSelected) {
this.nested.remove();
delete this.nested;
}
};
SVG.extend(SVG.Element, {
// Select element with mouse
selectize: function (value, options) {
// Check the parameters and reassign if needed
if (typeof value === 'object') {
options = value;
value = true;
}
var selectHandler = this.remember('_selectHandler') || new SelectHandler(this);
selectHandler.init(value === undefined ? true : value, options || {});
return this;
}
});
SVG.Element.prototype.selectize.defaults = {
points: ['lt', 'rt', 'rb', 'lb', 't', 'r', 'b', 'l'], // which points to draw, default all
pointsExclude: [], // easier option if to exclude few than rewrite all
classRect: 'svg_select_boundingRect', // Css-class added to the rect
classPoints: 'svg_select_points', // Css-class added to the points
pointSize: 7, // size of point
rotationPoint: true, // If true, rotation point is drawn. Needed for rotation!
deepSelect: false, // If true, moving of single points is possible (only line, polyline, polyon)
pointType: 'circle', // Point type: circle or rect, default circle
pointFill: "#000", // Point fill color
pointStroke: { width: 1, color: "#000" } // Point stroke properties
};
}());

File diff suppressed because one or more lines are too long

View file

@ -1,26 +0,0 @@
// Title Plugin
// Source: https://github.com/wout/svg.js/issues/147
//
// // example usage
// var draw = SVG('drawing')
// var group = draw.group()
// group.title('This is a pink square.')
// group.rect(100,100).fill('#f06')
SVG.Title = SVG.invent({
create: 'title',
inherit: SVG.Element,
extend: {
text: function(text) {
while (this.node.firstChild)
this.node.removeChild(this.node.firstChild)
this.node.appendChild(document.createTextNode(text))
return this
}
},
construct: {
title: function(text) {
return this.put(new SVG.Title).text(text)
}
}
})

View file

@ -1,17 +1,19 @@
"use strict";
var svg;
var data = {
rooms: [],
sensors: [],
events: []
};
var editModeEnabled = false;
$(function(){
if (!SVG.supported) {
alert("Image format(SVG) not supported by your browser.");
return;
}
// ------------------------------------------
// Setup map
// ------------------------------------------
svg = SVG("map");
svg = SVG("#map").size("100%", "700").viewbox(0, 0, 1000, 700);
// Initialize events
@ -58,7 +60,7 @@ $(function(){
$("#bg-file-progress").addClass("progress-bar-danger");
},
onProgress: function(t){
$("#bg-file-progress").css("width", t+"%");
$("#bg-file-progress").css("width", t + "%");
},
}
});
@ -67,114 +69,171 @@ $(function(){
// Start draw loop
// ------------------------------------------
fetchData(drawMap);
setInterval(function() {
if (editModeEnabled == false)
drawMap();
if (editModeEnabled == false) {
fetchData(drawMap);
}
}, 3000); // 3 sec
//}, 10000); // 10 sec
});
// ----------------------------------------------
// Events
// ----------------------------------------------
function editMode(enable){
if (editModeEnabled == enable)
if (editModeEnabled == enable) {
return;
}
editModeEnabled = enable;
if (editModeEnabled){
if (editModeEnabled) {
$(".edit-mode").show();
$(".view-mode").hide();
$("#map").css("border-color", "#6eb16e");
svg.select(".draggable").draggable(true);
}
else {
} else {
$(".room").selectize(false)
$(".edit-mode").hide();
$(".view-mode").show();
$("#map").css("border-color", "");
svg.select(".draggable").draggable(false);
}
}
function drawMap(){
// Get map data
$.getJSON("/api/map?action=getdata", function(json){
// Reset map
svg.clear();
function beforeDragEvent(e) {
if (editModeEnabled == false) {
e.preventDefault(); // Prevent drag
}
}
// --------------------------------------
// Draw
// --------------------------------------
function selectEntity(e) {
if (editModeEnabled == false) {
e.target.selectize();
}
}
// Background
// --------------------------------------
// Draw
// --------------------------------------
if (SVG.find("svg .bg-image").length > 0) {
var bg_image = svg.image("?bgimage").addClass("bg-image")
.x(0)
.y(0)
.width("100%")
.height("100%");
}
function drawMap() {
// Reset map
//svg.clear();
// Rooms
// Background
if (json.rooms != null) {
$.each(json.rooms, function(i, room) {
var group = svg.group();
if (svg.find(".bg-image").length <= 0) {
var bgImage = svg.image("?bgimage").addClass("bg-image")
.x(0)
.y(0)
.width("100%")
.height("100%");
}
group.rect(room.width, room.height);
group.text(room.name).move(10, 10).fill('#999');
// Rooms
group.addClass("draggable").addClass("room")
.x(room.x)
.y(room.y)
.attr("room-id", room.id);
});
}
if (data.rooms != null) {
$.each(data.rooms, function(i, room) {
svg.find("#room-" + room.id).remove();
// Sensors
var group = svg.group();
if (json.sensors != null) {
$.each(json.sensors, function(i, sensor) {
var group = svg.group();
group.text(room.name).move(5, 5).fill('#999');
group.rect(room.map.width, room.map.height).selectize();
group.image("/img/temperature.svg");
group.text(sensor.data).move(45, 15).fill('#999');
group.addClass("room")
.attr("id", "room-" + room.id)
.attr("room-id", room.id)
.x(room.map.x)
.y(room.map.y);
group.addClass("draggable").addClass("sensor")
.x(sensor.x)
.y(sensor.y)
.attr("sensor-id", sensor.id);
group.title(sensor.name);
});
}
group.draggable().on('beforedrag', beforeDragEvent);
//group.on('mousedown', selectEntity, false);
});
}
// Events
// Sensors
if (json.event != null) {
$.each(json.events, function(i, event) {
var group = svg.group();
if (data.sensors != null) {
$.each(data.sensors, function(i, sensor) {
svg.find("#sensor-" + sensor.id).remove();
var img = "/img/lightbulb_off.svg";
if (event.data == "ON")
img = "/img/lightbulb_on.svg";
group.image(img);
var group = svg.group();
group.element('title').words(sensor.name);
group.addClass("draggable").addClass("event")
.x(event.x)
.y(event.y)
.attr("event-id", event.id);
group.title(event.name);
});
}
});
group.text(sensor.data.valueStr).move(45, 15).fill('#999');
group.image("/img/temperature.svg").size(50, 50);
group.addClass("sensor")
.attr("id", "sensor-" + sensor.id)
.attr("sensor-id", sensor.id)
.x(sensor.map.x)
.y(sensor.map.y);
group.draggable().on('beforedrag', beforeDragEvent);
});
}
// Events
if (data.events != null) {
$.each(data.events, function(i, event) {
svg.find("#event-" + event.id).remove();
var group = svg.group();
group.element('title').words(event.name);
var img = "/img/lightbulb_off.svg";
if (event.data.valueStr == "ON")
img = "/img/lightbulb_on.svg";
group.image(img).size(50, 50);
group.addClass("event")
.attr("id", "event-" + event.id)
.attr("event-id", event.id)
.x(event.map.x)
.y(event.map.y);
group.draggable().on('beforedrag', beforeDragEvent);
});
}
}
// ----------------------------------------------
// Load and Store data
// ----------------------------------------------
async function fetchData(callback) {
await fetch('/api/room')
.then(response => response.json())
.then(json => {
data.rooms = json;
})
await fetch('/api/sensor')
.then(response => response.json())
.then(json => {
data.sensors = json;
})
await fetch('/api/event')
.then(response => response.json())
.then(json => {
data.events = json;
})
callback();
}
function saveMap(){
svg.select(".room").each(function(){
svg.find(".room").each(function(){
saveDevice(this, "room", "room-id");
});
svg.select(".sensor").each(function(){
svg.find(".sensor").each(function(){
saveDevice(this, "sensor", "sensor-id");
});
svg.select(".event").each(function(){
svg.find(".event").each(function(){
saveDevice(this, "event", "event-id");
});
}
@ -191,4 +250,4 @@ function saveDevice(element, type, id){
y: element.y()
},
});
}
}

View file

@ -13,8 +13,9 @@
</style>
<div class="col-sm-9 col-sm-offset-1 col-md-10 col-md-offset-1">
<svg id="map" width="100%" width="500" viewBox="0 0 1000 500"></svg>
<svg id="map"></svg>
</div>
<div class="col-sm-1 col-md-1">
<a id="button-edit" class="view-mode" href="#">
<span class="view-mode glyphicon glyphicon-wrench" aria-hidden="true"></span>
@ -41,16 +42,18 @@
</div>
</div>
<script src="js/lib/svg.min.js"></script>
<script src="js/lib/svg.title.js"></script>
<script src="js/lib/svg.draggable.min.js"></script>
<script src="js/lib/jquery.filer.min.js"></script>
<link href="css/jquery.filer.css" rel="stylesheet">
<link href="css/svg.select.min.js" 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.draggable.min.js"></script>
<script src="js/map.js"></script>
<!------------------ MODALS ---------------------->
<div class="modal fade" id="bgUploadModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">

View file

@ -30,9 +30,9 @@ public class HalContext {
public static final String RESOURCE_ROOT;
static {
if (FileUtil.find("build/resources/") != null)
if (FileUtil.find("build/resources/") != null) // Development environment
RESOURCE_ROOT = "build/resources";
else if (FileUtil.find("resources/") != null)
else if (FileUtil.find("resources/") != null) // Release package environment
RESOURCE_ROOT = "resources";
else
RESOURCE_ROOT = ".";

View file

@ -223,8 +223,8 @@ public abstract class HalAbstractDevice<V extends HalAbstractDevice, C extends H
return mapY;
}
public void setMapCoordinates(double x, double y) {
this.mapX = x;
this.mapY = y;
this.mapX = Math.max(0.0, x);
this.mapY = Math.max(0.0, y);
}
public void addReportListener(HalDeviceReportListener listener) {

View file

@ -33,9 +33,7 @@ public class MapApiEndpoint extends HalApiEndpoint {
DBConnection db = HalContext.getDB();
DataNode root = new DataNode(DataNode.DataType.Map);
if ("getdata".equals(request.get("action"))) {
getDeviceNode(db, root);
} else if ("save".equals(request.get("action"))) {
if ("save".equals(request.get("action"))) {
int id = Integer.parseInt(request.get("id"));
HalAbstractDevice device = null;
@ -46,40 +44,11 @@ public class MapApiEndpoint extends HalApiEndpoint {
else if ("event".equals(request.get("type")))
device = Event.getEvent(db, id);
device.setMapCoordinates(Float.parseFloat(request.get("x")), Float.parseFloat(request.get("y")));
device.setMapCoordinates(
Float.parseFloat(request.get("x")),
Float.parseFloat(request.get("y")));
device.save(db);
}
return root;
}
private void getDeviceNode(DBConnection db, DataNode root) throws SQLException {
DataNode sensorsNode = new DataNode(DataNode.DataType.List);
for (Sensor sensor : Sensor.getLocalSensors(db)) {
DataNode sensorNode = getDeviceNode(sensor);
sensorNode.set("data", ""+sensor.getDeviceData());
sensorsNode.add(sensorNode);
}
root.set("sensors", sensorsNode);
DataNode eventsNode = new DataNode(DataNode.DataType.List);
for (Event event : Event.getLocalEvents(db)) {
DataNode eventNode = getDeviceNode(event);
eventNode.set("data", ""+event.getDeviceData());
eventsNode.add(eventNode);
}
root.set("events", eventsNode);
}
private DataNode getDeviceNode(HalAbstractDevice device) {
DataNode deviceNode = new DataNode(DataNode.DataType.Map);
deviceNode.set("id", device.getId());
deviceNode.set("name", device.getName());
deviceNode.set("x", device.getMapX());
deviceNode.set("y", device.getMapY());
return deviceNode;
}
}