MDL-51914 qtype_ddmarker: precise grading round the edges of zones

There was a previous change to the CSS (7px -> 3px) to make things
look prettier, which acutally broke the grading by a few pixes.
I fixed this by:

* Changing the offset of the cross hairs back to the correct value,
  and adding a comment to point out the imporance of not changing
  that CSS.

* Achieved the nice layout of the label relative to the cross-hairs
  in a different way.

* Added a similar clafirying comment in the JavaScript.

* Improved how the grid on the editing form is aligned with the
  background image.

* Added rounding to the grading code, to cope better now that
  browsers do sub-pixel positioning.
This commit is contained in:
Tim Hunt 2015-10-26 17:40:26 +00:00
parent 9382ac38d6
commit 2d391d1b10
9 changed files with 15 additions and 7 deletions

View file

@ -214,6 +214,8 @@ class qtype_ddmarker_question extends qtype_ddtoimage_question_base {
continue; continue;
} }
$pointxy = explode(',', $coord); $pointxy = explode(',', $coord);
$pointxy[0] = round($pointxy[0]);
$pointxy[1] = round($pointxy[1]);
if ($place->drop_hit($pointxy)) { if ($place->drop_hit($pointxy)) {
if (!isset($hits[$placeno])) { if (!isset($hits[$placeno])) {
$hits[$placeno] = array(); $hits[$placeno] = array();

View file

@ -40,7 +40,7 @@ form.mform fieldset#id_previewareaheader div.draghome, form.mform fieldset#id_pr
.que.ddmarker div.dragitems span.markertext, .que.ddmarker div.dragitems span.markertext,
.que.ddmarker div.markertexts span.markertext, .que.ddmarker div.markertexts span.markertext,
form.mform fieldset#id_previewareaheader div.markertexts span.markertext { form.mform fieldset#id_previewareaheader div.markertexts span.markertext {
margin: 5px; margin: 0 5px;
z-index: 3; z-index: 3;
background-color: white; background-color: white;
border: 2px solid black; border: 2px solid black;
@ -70,8 +70,8 @@ form.mform fieldset#id_previewareaheader div.markertexts span.markertext {
} }
.que.ddmarker div.dragitems img.target { .que.ddmarker div.dragitems img.target {
position: absolute; position: absolute;
left: -7px; left: -7px; /* This must be half the size of the target image, minus 0.5. */
top: -3px; top: -7px; /* In other words, this works for a 15x15 cross-hair. */
} }
.que.ddmarker div.dragitems div.draghome img.target { .que.ddmarker div.dragitems div.draghome img.target {
display: none; display: none;

View file

@ -133,6 +133,8 @@ Y.extend(DDMARKER_DD, Y.Base, {
return colour; return colour;
}, },
convert_to_window_xy : function (bgimgxy) { convert_to_window_xy : function (bgimgxy) {
// The +1 seems rather odd, but seems to give the best results in
// the three main browsers at a range of zoom levels.
return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1, return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1,
Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1]; Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1];
}, },

View file

@ -133,6 +133,8 @@ Y.extend(DDMARKER_DD, Y.Base, {
return colour; return colour;
}, },
convert_to_window_xy : function (bgimgxy) { convert_to_window_xy : function (bgimgxy) {
// The +1 seems rather odd, but seems to give the best results in
// the three main browsers at a range of zoom levels.
return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1, return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1,
Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1]; Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1];
}, },

View file

@ -98,7 +98,7 @@ Y.extend(DDMARKER_FORM, M.qtype_ddmarker.dd_base_class, {
} }
if (this.doc.bg_img()) { if (this.doc.bg_img()) {
Y.one('div.ddarea .grid') Y.one('div.ddarea .grid')
.setXY(this.doc.bg_img().getXY()) .setXY(this.convert_to_window_xy([0, 0]))
.setStyle('width', this.doc.bg_img().get('width')) .setStyle('width', this.doc.bg_img().get('width'))
.setStyle('height', this.doc.bg_img().get('height')); .setStyle('height', this.doc.bg_img().get('height'));
} }

View file

@ -1 +1 @@
YUI.add("moodle-qtype_ddmarker-form",function(e,t){var n="moodle-qtype_ddmarker-form",r=function(){r.superclass.constructor.apply(this,arguments)};e.extend(r,M.qtype_ddmarker.dd_base_class,{fp:null,initializer:function(){var t="qtype_ddmarker-form-"+Math.random().toString(36).slice(2);M.util.js_pending(t),this.fp=this.file_pickers();var n=e.one(this.get("topnode"));n.one("div.fcontainer").append('<div class="ddarea"><div class="markertexts"></div><div class="droparea"></div><div class="dropzones"></div><div class="grid"></div></div>'),this.doc=this.doc_structure(this),this.stop_selector_events(),this.set_options_for_drag_item_selectors(),this.setup_form_events(),e.later(500,this,this.update_drop_zones,[t],!0),e.after(this.load_bg_image,M.form_filepicker,"callback",this),this.load_bg_image()},load_bg_image:function(){var t=this.fp.file("bgimage").href;if(t!==null){this.doc.load_bg_img(t);var n=new e.DD.Drop({node:this.doc.bg_img()});n.on("drop:hit",function(e){e.drag.get("node").setData("gooddrop",!0)}),this.afterimageloaddone=!1,this.doc.bg_img().on("load",this.constrain_image_size,this)}},constrain_image_size:function(e){var t=this.get("maxsizes").bgimage,n=Math.max(e.target.get("width")/t.width,e.target.get("height")/t.height);n>1&&e.target.set("width",Math.floor(e.target.get("width")/n)),e.target.addClass("constrained"),e.target.detach("load",this.constrain_image_size)},update_drop_zones:function(t){this.graphics!==null&&this.graphics.destroy(),this.restart_colours(),this.graphics=new e.Graphic({render:"div.ddarea div.dropzones"});var n=this.form.get_form_value("nodropzone",[]);for(var r=0;r<n;r++){var i=this.form.get_form_value("drops",[r,"choice"]),s=this.get_marker_text(i),o=this.form.get_form_value("drops",[r,"shape"]),u=this.get_coords(r),a=this.get_next_colour();e.one("input#id_drops_"+r+"_coords").setStyle("background-color",a),this.draw_drop_zone(r,s,o,u,a,!1)}this.doc.bg_img()&&e.one("div.ddarea .grid").setXY(this.doc.bg_img().getXY()).setStyle("width",this.doc.bg_img().get("width")).setStyle("height",this.doc.bg_img().get("height")),M.util.js_complete(t)},get_coords:function(e){var t=this.form.get_form_value("drops",[e,"coords"]);return t.replace(new RegExp("\\s*","g"),"")},get_marker_text:function(e){if(Number(e)!==0){var t=this.form.get_form_value("drags",[e-1,"label"]);return t.replace(new RegExp("^\\s*(.*)\\s*$"),"$1")}return""},set_options_for_drag_item_selectors:function(){var t={0:""};for(var n=1;n<=this.form.get_form_value("noitems",[]);n++){var r=this.get_marker_text(n);r!==""&&(t[n]=e.Escape.html(r))}var i=[],s;for(n=0;n<this.form.get_form_value("nodropzone",[]);n++)s=e.one("#id_drops_"+n+"_choice"),i[n]=Number(s.get("value"));for(n=0;n<this.form.get_form_value("nodropzone",[]);n++){s=e.one("#id_drops_"+n+"_choice"),s.all("option").remove(!0);for(var o in t){o=Number(o);var u='<option value="'+o+'">'+t[o]+"</option>";s.append(u);var a=s.one('option[value="'+o+'"]');if(o===i[n])a.set("selected",!0);else if(o!==0){var f=this.form.get_form_value("drags",[o-1,"noofdrags"]);if(Number(f)!==0)for(var l in i)if(Number(i[l])===o){if(Number(f)===1){a.set("disabled",!0);break}f--}}}}},stop_selector_events:function(){e.all("fieldset#id_dropzoneheader select").detachAll()},setup_form_events:function(){e.all("fieldset#id_draggableitemheader input").on("change",function(){this.set_options_for_drag_item_selectors()},this),e.all("fieldset#id_draggableitemheader select").on("change",function(){this.set_options_for_drag_item_selectors()},this),e.all("fieldset#id_dropzoneheader select").on("change",function(){this.set_options_for_drag_item_selectors()},this)},form:{to_name_with_index:function(e,t){var n=e;for(var r=0;r<t.length;r++)n=n+"["+t[r]+"]";return n},get_el:function(e,t){var n=document.getElementById("mform1");return n.elements[this.to_name_with_index(e,t)]},get_form_value:function(e,t){var n=this.get_el(e,t);return n.type==="checkbox"?n.checked:n.value},set_form_value:function(e,t,n){var r=this.get_el(e,t);r.type==="checkbox"?r.checked=n:r.value=n},from_name_with_index:function(e){var t={};t.indexes=[];var n=e.indexOf("[");t.name=e.substring(0,n);while(n!==-1){var r=e.indexOf("]",n+1);t.indexes.push(e.substring(n+1,r)),n=e.indexOf("[",r+1)}return t}},file_pickers:function(){var t,n;if(t===undefined){t={},n={};var r=e.all("form.mform input.filepickerhidden");r.each(function(e){t[e.get("value")]=e.get("name"),n[e.get("name")]=e.get("parentNode")},this)}var i={file:function(e){var t=n[e],r=t.one("div.filepicker-filelist a");return r?{href:r.get("href"),name:r.get("innerHTML")}:{href:null,name:null}},name:function(e){return t[e]}};return i}},{NAME:n,ATTRS:{maxsizes:{value:null}}}),M.qtype_ddmarker=M.qtype_ddmarker||{},M.qtype_ddmarker.init_form=function(e){return new r(e)}},"@VERSION@",{requires:["moodle-qtype_ddmarker-dd","form_filepicker","graphics","escape"]}); YUI.add("moodle-qtype_ddmarker-form",function(e,t){var n="moodle-qtype_ddmarker-form",r=function(){r.superclass.constructor.apply(this,arguments)};e.extend(r,M.qtype_ddmarker.dd_base_class,{fp:null,initializer:function(){var t="qtype_ddmarker-form-"+Math.random().toString(36).slice(2);M.util.js_pending(t),this.fp=this.file_pickers();var n=e.one(this.get("topnode"));n.one("div.fcontainer").append('<div class="ddarea"><div class="markertexts"></div><div class="droparea"></div><div class="dropzones"></div><div class="grid"></div></div>'),this.doc=this.doc_structure(this),this.stop_selector_events(),this.set_options_for_drag_item_selectors(),this.setup_form_events(),e.later(500,this,this.update_drop_zones,[t],!0),e.after(this.load_bg_image,M.form_filepicker,"callback",this),this.load_bg_image()},load_bg_image:function(){var t=this.fp.file("bgimage").href;if(t!==null){this.doc.load_bg_img(t);var n=new e.DD.Drop({node:this.doc.bg_img()});n.on("drop:hit",function(e){e.drag.get("node").setData("gooddrop",!0)}),this.afterimageloaddone=!1,this.doc.bg_img().on("load",this.constrain_image_size,this)}},constrain_image_size:function(e){var t=this.get("maxsizes").bgimage,n=Math.max(e.target.get("width")/t.width,e.target.get("height")/t.height);n>1&&e.target.set("width",Math.floor(e.target.get("width")/n)),e.target.addClass("constrained"),e.target.detach("load",this.constrain_image_size)},update_drop_zones:function(t){this.graphics!==null&&this.graphics.destroy(),this.restart_colours(),this.graphics=new e.Graphic({render:"div.ddarea div.dropzones"});var n=this.form.get_form_value("nodropzone",[]);for(var r=0;r<n;r++){var i=this.form.get_form_value("drops",[r,"choice"]),s=this.get_marker_text(i),o=this.form.get_form_value("drops",[r,"shape"]),u=this.get_coords(r),a=this.get_next_colour();e.one("input#id_drops_"+r+"_coords").setStyle("background-color",a),this.draw_drop_zone(r,s,o,u,a,!1)}this.doc.bg_img()&&e.one("div.ddarea .grid").setXY(this.convert_to_window_xy([0,0])).setStyle("width",this.doc.bg_img().get("width")).setStyle("height",this.doc.bg_img().get("height")),M.util.js_complete(t)},get_coords:function(e){var t=this.form.get_form_value("drops",[e,"coords"]);return t.replace(new RegExp("\\s*","g"),"")},get_marker_text:function(e){if(Number(e)!==0){var t=this.form.get_form_value("drags",[e-1,"label"]);return t.replace(new RegExp("^\\s*(.*)\\s*$"),"$1")}return""},set_options_for_drag_item_selectors:function(){var t={0:""};for(var n=1;n<=this.form.get_form_value("noitems",[]);n++){var r=this.get_marker_text(n);r!==""&&(t[n]=e.Escape.html(r))}var i=[],s;for(n=0;n<this.form.get_form_value("nodropzone",[]);n++)s=e.one("#id_drops_"+n+"_choice"),i[n]=Number(s.get("value"));for(n=0;n<this.form.get_form_value("nodropzone",[]);n++){s=e.one("#id_drops_"+n+"_choice"),s.all("option").remove(!0);for(var o in t){o=Number(o);var u='<option value="'+o+'">'+t[o]+"</option>";s.append(u);var a=s.one('option[value="'+o+'"]');if(o===i[n])a.set("selected",!0);else if(o!==0){var f=this.form.get_form_value("drags",[o-1,"noofdrags"]);if(Number(f)!==0)for(var l in i)if(Number(i[l])===o){if(Number(f)===1){a.set("disabled",!0);break}f--}}}}},stop_selector_events:function(){e.all("fieldset#id_dropzoneheader select").detachAll()},setup_form_events:function(){e.all("fieldset#id_draggableitemheader input").on("change",function(){this.set_options_for_drag_item_selectors()},this),e.all("fieldset#id_draggableitemheader select").on("change",function(){this.set_options_for_drag_item_selectors()},this),e.all("fieldset#id_dropzoneheader select").on("change",function(){this.set_options_for_drag_item_selectors()},this)},form:{to_name_with_index:function(e,t){var n=e;for(var r=0;r<t.length;r++)n=n+"["+t[r]+"]";return n},get_el:function(e,t){var n=document.getElementById("mform1");return n.elements[this.to_name_with_index(e,t)]},get_form_value:function(e,t){var n=this.get_el(e,t);return n.type==="checkbox"?n.checked:n.value},set_form_value:function(e,t,n){var r=this.get_el(e,t);r.type==="checkbox"?r.checked=n:r.value=n},from_name_with_index:function(e){var t={};t.indexes=[];var n=e.indexOf("[");t.name=e.substring(0,n);while(n!==-1){var r=e.indexOf("]",n+1);t.indexes.push(e.substring(n+1,r)),n=e.indexOf("[",r+1)}return t}},file_pickers:function(){var t,n;if(t===undefined){t={},n={};var r=e.all("form.mform input.filepickerhidden");r.each(function(e){t[e.get("value")]=e.get("name"),n[e.get("name")]=e.get("parentNode")},this)}var i={file:function(e){var t=n[e],r=t.one("div.filepicker-filelist a");return r?{href:r.get("href"),name:r.get("innerHTML")}:{href:null,name:null}},name:function(e){return t[e]}};return i}},{NAME:n,ATTRS:{maxsizes:{value:null}}}),M.qtype_ddmarker=M.qtype_ddmarker||{},M.qtype_ddmarker.init_form=function(e){return new r(e)}},"@VERSION@",{requires:["moodle-qtype_ddmarker-dd","form_filepicker","graphics","escape"]});

View file

@ -98,7 +98,7 @@ Y.extend(DDMARKER_FORM, M.qtype_ddmarker.dd_base_class, {
} }
if (this.doc.bg_img()) { if (this.doc.bg_img()) {
Y.one('div.ddarea .grid') Y.one('div.ddarea .grid')
.setXY(this.doc.bg_img().getXY()) .setXY(this.convert_to_window_xy([0, 0]))
.setStyle('width', this.doc.bg_img().get('width')) .setStyle('width', this.doc.bg_img().get('width'))
.setStyle('height', this.doc.bg_img().get('height')); .setStyle('height', this.doc.bg_img().get('height'));
} }

View file

@ -131,6 +131,8 @@ Y.extend(DDMARKER_DD, Y.Base, {
return colour; return colour;
}, },
convert_to_window_xy : function (bgimgxy) { convert_to_window_xy : function (bgimgxy) {
// The +1 seems rather odd, but seems to give the best results in
// the three main browsers at a range of zoom levels.
return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1, return [Number(bgimgxy[0]) + this.doc.bg_img().getX() + 1,
Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1]; Number(bgimgxy[1]) + this.doc.bg_img().getY() + 1];
}, },

View file

@ -96,7 +96,7 @@ Y.extend(DDMARKER_FORM, M.qtype_ddmarker.dd_base_class, {
} }
if (this.doc.bg_img()) { if (this.doc.bg_img()) {
Y.one('div.ddarea .grid') Y.one('div.ddarea .grid')
.setXY(this.doc.bg_img().getXY()) .setXY(this.convert_to_window_xy([0, 0]))
.setStyle('width', this.doc.bg_img().get('width')) .setStyle('width', this.doc.bg_img().get('width'))
.setStyle('height', this.doc.bg_img().get('height')); .setStyle('height', this.doc.bg_img().get('height'));
} }