diff --git a/question/type/ddmarker/amd/build/form.min.js b/question/type/ddmarker/amd/build/form.min.js index 4f5c5e71a7a..4843ef708f7 100644 --- a/question/type/ddmarker/amd/build/form.min.js +++ b/question/type/ddmarker/amd/build/form.min.js @@ -1 +1 @@ -define(["jquery","core/dragdrop","qtype_ddmarker/shapes"],function(a,b,c){"use strict";function d(a){this.dropzoneNo=a,this.svgEl=null,this.shape=c.make(this.getShapeType(),this.getLabel()),this.updateCoordinatesFromForm()}d.prototype.updateCoordinatesFromForm=function(){var a=this.getCoordinates();this.shape.getCoordinates()!==a&&this.shape.parse(a)&&this.updateSvgEl()},d.prototype.updateLabel=function(){var a=this.getLabel();this.shape.label!==a&&(this.shape.label=a,this.updateSvgEl())},d.prototype.changeShape=function(a){var b=this.getShapeType(),d=this.isActive();b!==this.shape.getType()&&(this.removeFromSvg(),this.shape=c.getSimilar(b,this.shape),a&&(this.addToSvg(a),d&&this.setActive()),this.setCoordinatesInForm())},d.prototype.addToSvg=function(a){if(null!==this.svgEl)throw new Error("this.svgEl already set");if(this.svgEl=this.shape.makeSvg(a),this.svgEl){this.svgEl.setAttribute("class","dropzone"),this.svgEl.setAttribute("data-dropzone-no",this.dropzoneNo);var b=this.shape.getHandlePositions();if(null!==b){var d=c.createSvgElement(this.svgEl,"circle");d.setAttribute("cx",b.moveHandle.x),d.setAttribute("cy",b.moveHandle.y),d.setAttribute("r",7),d.setAttribute("class","handle move");for(var e=0;e
')},setOptionsForDragItemSelectors:function(){var b,c,d,f={0:""},g=e.form.getFormValue("noitems",[]),h=[];for(c=1;c<=g;c++)d=e.form.getMarkerText(c),""!==d&&(f[c]=a("
").text(d).html());for(c=0;c'+f[i]+"";b.append(j);var k=b.find('option[value="'+i+'"]');if(0!==i)if(i!==h[c]){var l=e.form.getFormValue("drags",[i-1,"noofdrags"]);if(0!==Number(l))for(var m in h)if(Number(h[m])===i){if(1===Number(l)){k.attr("disabled",!0);break}l--}}else k.attr("selected",!0)}e.dropZones.length>0&&e.dropZones[c].updateLabel()}},createShapes:function(){for(var a=0;a1&&b.css("width",Math.floor(b.width()/c)),b.addClass("constrained")},updateSvgDisplay:function(){var b,c=a("fieldset#id_previewareaheader .dropbackground");if(e.form.getSvg())for(b=0;b'),b=0;b
')},setOptionsForDragItemSelectors:function(){var b,c,d,f={0:""},g=e.form.getFormValue("noitems",[]),h=[];for(c=1;c<=g;c++)d=e.form.getMarkerText(c),""!==d&&(f[c]=a("
").text(d).html());for(c=0;c'+f[i]+"";b.append(j);var k=b.find('option[value="'+i+'"]');if(0!==i)if(i!==h[c]){var l=e.form.getFormValue("drags",[i-1,"noofdrags"]);if(0!==Number(l))for(var m in h)if(Number(h[m])===i){if(1===Number(l)){k.attr("disabled",!0);break}l--}}else k.attr("selected",!0)}e.dropZones.length>0&&e.dropZones[c].updateLabel()}},createShapes:function(){for(var a=0;a1&&b.css("width",Math.floor(b.width()/c)),b.addClass("constrained")},updateSvgDisplay:function(){var b,c=a("fieldset#id_previewareaheader .dropbackground");if(e.form.getSvg())for(b=0;b'),b=0;b=0?(a.childNodes[0].setAttribute("x",this.centre.x),a.childNodes[0].setAttribute("width",this.width)):(a.childNodes[0].setAttribute("x",this.centre.x+this.width),a.childNodes[0].setAttribute("width",-this.width)),this.height>=0?(a.childNodes[0].setAttribute("y",this.centre.y),a.childNodes[0].setAttribute("height",this.height)):(a.childNodes[0].setAttribute("y",this.centre.y+this.height),a.childNodes[0].setAttribute("height",-this.height)),a.childNodes[1].setAttribute("x",this.centre.x+this.width/2),a.childNodes[1].setAttribute("y",this.centre.y+this.height/2+15),a.childNodes[1].textContent=this.label},d.prototype.parse=function(b){if(!b.match(/\d+,\d+;\d+,\d+/))return!1;var c=b.split(";");this.centre=a.parse(c[0]);var d=a.parse(c[1]);return this.width=d.x,this.height=d.y,!0},d.prototype.edit=function(a,b,c){this.width+=b,this.height+=c},d.prototype.normalizeShape=function(){this.width<0&&(this.centre.x+=this.width,this.width=-this.width),this.height<0&&(this.centre.y+=this.height,this.height=-this.height)},d.prototype.makeSimilarCircle=function(){return new c(this.label,Math.round(this.centre.x+this.width/2),Math.round(this.centre.y+this.height/2),Math.round((this.width+this.height)/4))},d.prototype.makeSimilarPolygon=function(){return new e(this.label,[this.centre,this.centre.offset(0,this.height),this.centre.offset(this.width,this.height),this.centre.offset(this.width,0)])},d.prototype.getHandlePositions=function(){return{moveHandle:this.centre.offset(this.width/2,this.height/2),editHandles:[this.centre.offset(this.width,this.height)]}},e.prototype=new b,e.prototype.getType=function(){return"polygon"},e.prototype.getCoordinates=function(){for(var a="",b=0;bc-this.radius&&(this.centre.x=c-this.radius),this.centre.yd-this.radius&&(this.centre.y=d-this.radius)},c.prototype.edit=function(a,b,c,d,e){this.radius+=b;var f=Math.min(this.centre.x,this.centre.y,d-this.centre.x,e-this.centre.y);this.radius>f&&(this.radius=f),this.radius<-f&&(this.radius=-f)},c.prototype.normalizeShape=function(){this.radius=Math.abs(this.radius)},c.prototype.makeSimilarRectangle=function(){return new d(this.label,this.centre.x-this.radius,this.centre.y-this.radius,2*this.radius,2*this.radius)},c.prototype.makeSimilarPolygon=function(){return new e(this.label,[this.centre.offset(-this.radius,-this.radius),this.centre.offset(-this.radius,this.radius),this.centre.offset(this.radius,this.radius),this.centre.offset(this.radius,-this.radius)])},c.prototype.getHandlePositions=function(){return{moveHandle:this.centre,editHandles:[this.centre.offset(this.radius,0)]}},d.prototype=new b,d.prototype.getType=function(){return"rectangle"},d.prototype.getCoordinates=function(){return this.centre+";"+this.width+","+this.height},d.prototype.makeSvg=function(a){var b=h(a,"rect");return this.updateSvg(b),b},d.prototype.updateSvg=function(a){this.width>=0?(a.childNodes[0].setAttribute("x",this.centre.x),a.childNodes[0].setAttribute("width",this.width)):(a.childNodes[0].setAttribute("x",this.centre.x+this.width),a.childNodes[0].setAttribute("width",-this.width)),this.height>=0?(a.childNodes[0].setAttribute("y",this.centre.y),a.childNodes[0].setAttribute("height",this.height)):(a.childNodes[0].setAttribute("y",this.centre.y+this.height),a.childNodes[0].setAttribute("height",-this.height)),a.childNodes[1].setAttribute("x",this.centre.x+this.width/2),a.childNodes[1].setAttribute("y",this.centre.y+this.height/2+15),a.childNodes[1].textContent=this.label},d.prototype.parse=function(b){if(!b.match(/^\d+,\d+;\d+,\d+$/))return!1;var c=b.split(";");this.centre=a.parse(c[0]);var d=a.parse(c[1]);return this.width=d.x,this.height=d.y,!0},d.prototype.move=function(a,b,c,d){this.centre.move(a,b),this.centre.x<0&&(this.centre.x=0),this.centre.x>c-this.width&&(this.centre.x=c-this.width),this.centre.y<0&&(this.centre.y=0),this.centre.y>d-this.height&&(this.centre.y=d-this.height)},d.prototype.edit=function(a,b,c,d,e){this.width+=b,this.height+=c,this.width<-this.centre.x&&(this.width=-this.centre.x),this.width>d-this.centre.x&&(this.width=d-this.centre.x),this.height<-this.centre.y&&(this.height=-this.centre.y),this.height>e-this.centre.y&&(this.height=e-this.centre.y)},d.prototype.normalizeShape=function(){this.width<0&&(this.centre.x+=this.width,this.width=-this.width),this.height<0&&(this.centre.y+=this.height,this.height=-this.height)},d.prototype.makeSimilarCircle=function(){return new c(this.label,Math.round(this.centre.x+this.width/2),Math.round(this.centre.y+this.height/2),Math.round((this.width+this.height)/4))},d.prototype.makeSimilarPolygon=function(){return new e(this.label,[this.centre,this.centre.offset(0,this.height),this.centre.offset(this.width,this.height),this.centre.offset(this.width,0)])},d.prototype.getHandlePositions=function(){return{moveHandle:this.centre.offset(this.width/2,this.height/2),editHandles:[this.centre.offset(this.width,this.height)]}},e.prototype=new b,e.prototype.getType=function(){return"polygon"},e.prototype.getCoordinates=function(){for(var a="",b=0;bc-f&&(this.centre.x=c-f),this.centre.y<-g&&(this.centre.y=-g),this.centre.y>d-h&&(this.centre.y=d-h)},e.prototype.edit=function(a,b,c,d,e){this.points[a].move(b,c),this.points[a].x<-this.centre.x&&(this.points[a].x=-this.centre.x),this.points[a].x>d-this.centre.x&&(this.points[a].x=d-this.centre.x),this.points[a].y<-this.centre.y&&(this.points[a].y=-this.centre.y),this.points[a].y>e-this.centre.y&&(this.points[a].y=e-this.centre.y)},e.prototype.addNewPointAfter=function(b){this.points.splice(b,0,new a(this.points[b].x,this.points[b].y))},e.prototype.normalizeShape=function(){var a,b=0,c=0;if(0!==this.points.length){for(a=0;a maxX - this.radius) { + this.centre.x = maxX - this.radius; + } + if (this.centre.y < this.radius) { + this.centre.y = this.radius; + } + if (this.centre.y > maxY - this.radius) { + this.centre.y = maxY - this.radius; + } + }; + + Circle.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) { this.radius += dx; - void (dy); + var limit = Math.min(this.centre.x, this.centre.y, maxX - this.centre.x, maxY - this.centre.y); + if (this.radius > limit) { + this.radius = limit; + } + if (this.radius < -limit) { + this.radius = -limit; + } }; /** @@ -357,7 +383,7 @@ define(function() { }; Rectangle.prototype.parse = function(coordinates) { - if (!coordinates.match(/\d+,\d+;\d+,\d+/)) { + if (!coordinates.match(/^\d+,\d+;\d+,\d+$/)) { return false; } @@ -369,9 +395,37 @@ define(function() { return true; }; - Rectangle.prototype.edit = function(handleIndex, dx, dy) { + Rectangle.prototype.move = function(dx, dy, maxX, maxY) { + this.centre.move(dx, dy); + if (this.centre.x < 0) { + this.centre.x = 0; + } + if (this.centre.x > maxX - this.width) { + this.centre.x = maxX - this.width; + } + if (this.centre.y < 0) { + this.centre.y = 0; + } + if (this.centre.y > maxY - this.height) { + this.centre.y = maxY - this.height; + } + }; + + Rectangle.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) { this.width += dx; this.height += dy; + if (this.width < -this.centre.x) { + this.width = -this.centre.x; + } + if (this.width > maxX - this.centre.x) { + this.width = maxX - this.centre.x; + } + if (this.height < -this.centre.y) { + this.height = -this.centre.y; + } + if (this.height > maxY - this.centre.y) { + this.height = maxY - this.centre.y; + } }; /** @@ -452,7 +506,7 @@ define(function() { }; Polygon.prototype.parse = function(coordinates) { - if (!coordinates.match(/(?:\d+,\d+)?(?:;\d+,\d+)*/)) { + if (!coordinates.match(/^\d+,\d+(?:;\d+,\d+)*$/)) { return false; } @@ -470,8 +524,47 @@ define(function() { return true; }; - Polygon.prototype.edit = function(handleIndex, dx, dy) { + Polygon.prototype.move = function(dx, dy, maxX, maxY) { + this.centre.move(dx, dy); + var bbXMin = maxX, + bbXMax = 0, + bbYMin = maxY, + bbYMax = 0; + // Computer centre. + for (var i = 0; i < this.points.length; i++) { + bbXMin = Math.min(bbXMin, this.points[i].x); + bbXMax = Math.max(bbXMax, this.points[i].x); + bbYMin = Math.min(bbYMin, this.points[i].y); + bbYMax = Math.max(bbYMax, this.points[i].y); + } + if (this.centre.x < -bbXMin) { + this.centre.x = -bbXMin; + } + if (this.centre.x > maxX - bbXMax) { + this.centre.x = maxX - bbXMax; + } + if (this.centre.y < -bbYMin) { + this.centre.y = -bbYMin; + } + if (this.centre.y > maxY - bbYMax) { + this.centre.y = maxY - bbYMax; + } + }; + + Polygon.prototype.edit = function(handleIndex, dx, dy, maxX, maxY) { this.points[handleIndex].move(dx, dy); + if (this.points[handleIndex].x < -this.centre.x) { + this.points[handleIndex].x = -this.centre.x; + } + if (this.points[handleIndex].x > maxX - this.centre.x) { + this.points[handleIndex].x = maxX - this.centre.x; + } + if (this.points[handleIndex].y < -this.centre.y) { + this.points[handleIndex].y = -this.centre.y; + } + if (this.points[handleIndex].y > maxY - this.centre.y) { + this.points[handleIndex].y = maxY - this.centre.y; + } }; /** diff --git a/question/type/ddmarker/lang/en/qtype_ddmarker.php b/question/type/ddmarker/lang/en/qtype_ddmarker.php index b5fb062d3f5..41188596eac 100644 --- a/question/type/ddmarker/lang/en/qtype_ddmarker.php +++ b/question/type/ddmarker/lang/en/qtype_ddmarker.php @@ -42,7 +42,7 @@ First selecting a shape (circle, rectangle or polygon) will add a new drop zone Editing a shape starts with a click on the shape in the preview to show the editing handles. You can move the shape using the center handle, or adjust the shape\'s dimensions with the vertex handles. -For polygons only, holding the control button while clicking on a vertex handle will add a new vertex to the polygon. Please keep a polygon shape as simple as possible, without crossing lines. +For polygons only, holding the control button (command button on a Mac) while clicking on a vertex handle will add a new vertex to the polygon. Please keep a polygon shape as simple as possible, without crossing lines. For information the three shapes use coordinates in this way:
* Circle: centre_x, centre_y; radius
for example: 80,100;50
diff --git a/question/type/ddmarker/shapes.php b/question/type/ddmarker/shapes.php index e268d45bd1a..6be52a80dd8 100644 --- a/question/type/ddmarker/shapes.php +++ b/question/type/ddmarker/shapes.php @@ -42,7 +42,8 @@ abstract class qtype_ddmarker_shape { } public function inside_width_height($widthheight) { foreach ($this->outlying_coords_to_test() as $coordsxy) { - if ($coordsxy[0] > $widthheight[0] || $coordsxy[1] > $widthheight[1]) { + if ($coordsxy[0] < 0 || $coordsxy[0] > $widthheight[0] || + $coordsxy[1] < 0 || $coordsxy[1] > $widthheight[1]) { return false; } } @@ -236,7 +237,7 @@ class qtype_ddmarker_shape_rectangle extends qtype_ddmarker_shape { } protected function outlying_coords_to_test() { - return array($this->xleft + $this->width, $this->ytop + $this->height); + return [[$this->xleft, $this->ytop], [$this->xleft + $this->width, $this->ytop + $this->height]]; } public function is_point_in_shape($xy) { return $this->is_point_in_bounding_box($xy, array($this->xleft, $this->ytop), @@ -296,7 +297,8 @@ class qtype_ddmarker_shape_circle extends qtype_ddmarker_shape { } protected function outlying_coords_to_test() { - return array($this->xcentre + $this->radius, $this->ycentre + $this->radius); + return [[$this->xcentre - $this->radius, $this->ycentre - $this->radius], + [$this->xcentre + $this->radius, $this->ycentre + $this->radius]]; } public function is_point_in_shape($xy) {