commit
cf7ce472e0
@ -0,0 +1,15 @@ |
||||
#hotspot-container { |
||||
line-height: 0; |
||||
/*position: relative; |
||||
width: 100%; |
||||
vertical-align: middle; |
||||
padding-bottom: 408px; |
||||
margin: 0; |
||||
overflow: hidden;*/ |
||||
} |
||||
#hotspot-container svg { |
||||
/*display: inline-block; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0;*/ |
||||
} |
@ -0,0 +1,506 @@ |
||||
var HotSpotAdmin = (function () { |
||||
var HotSpotSquare = function () { |
||||
this.x = 0; |
||||
this.y = 0; |
||||
this.width = 0; |
||||
this.height = 0; |
||||
}; |
||||
HotSpotSquare.prototype.setStartPoint = function (x, y) { |
||||
this.x = parseInt(x); |
||||
this.y = parseInt(y); |
||||
}; |
||||
HotSpotSquare.prototype.setEndPoint = function (x, y) { |
||||
var x2, y2; |
||||
|
||||
x = parseInt(x); |
||||
y = parseInt(y); |
||||
|
||||
if (x < this.x) { |
||||
x2 = this.x; |
||||
this.x = x; |
||||
} else { |
||||
x2 = x; |
||||
} |
||||
|
||||
if (y < this.y) { |
||||
y2 = this.y; |
||||
this.y = y; |
||||
} else { |
||||
y2 = y; |
||||
} |
||||
|
||||
this.width = Math.round(x2 - this.x); |
||||
this.height = Math.round(y2 - this.y); |
||||
}; |
||||
HotSpotSquare.prototype.encode = function () { |
||||
var encodedPosition = [this.x, this.y].join(';'); |
||||
|
||||
return [ |
||||
encodedPosition, |
||||
this.width, |
||||
this.height |
||||
].join('|'); |
||||
} |
||||
|
||||
var HotSpotEllipse = function () { |
||||
this.centerX = 0; |
||||
this.centerY = 0; |
||||
this.radiusX = 0; |
||||
this.radiusY = 0; |
||||
}; |
||||
HotSpotEllipse.prototype.setStartPoint = function (x, y) { |
||||
this.centerX = parseInt(x); |
||||
this.centerY = parseInt(y); |
||||
}; |
||||
HotSpotEllipse.prototype.setEndPoint = function (x, y) { |
||||
var startX = this.centerX, |
||||
startY = this.centerY, |
||||
endX = 0, |
||||
endY = 0; |
||||
|
||||
x = parseInt(x); |
||||
y = parseInt(y); |
||||
|
||||
if (x < startX) { |
||||
endX = startX; |
||||
startX = x; |
||||
} else { |
||||
endX = x; |
||||
} |
||||
|
||||
if (y < startY) { |
||||
endY = startY; |
||||
startY = y; |
||||
} else { |
||||
endY = y; |
||||
} |
||||
|
||||
var width = Math.round(endX - startX); |
||||
var height = Math.round(endY - startY); |
||||
|
||||
this.radiusX = Math.round(width / 2); |
||||
this.radiusY = Math.round(height / 2); |
||||
this.centerX = startX + this.radiusX; |
||||
this.centerY = startY + this.radiusY; |
||||
}; |
||||
HotSpotEllipse.prototype.encode = function () { |
||||
var encodedCenter = [this.centerX, this.centerY].join(';'); |
||||
|
||||
return [ |
||||
encodedCenter, |
||||
this.radiusX, |
||||
this.radiusY |
||||
].join('|'); |
||||
}; |
||||
|
||||
var HotSpotPolygon = function () { |
||||
this.points = []; |
||||
}; |
||||
HotSpotPolygon.prototype.addPoint = function (x, y) { |
||||
this.points.push([ |
||||
parseInt(x), |
||||
parseInt(y) |
||||
]); |
||||
}; |
||||
HotSpotPolygon.prototype.encode = function () { |
||||
var encodedPoints = []; |
||||
|
||||
this.points.forEach(function (point) { |
||||
encodedPoints.push(point.join(';')); |
||||
}); |
||||
|
||||
return encodedPoints.join('|'); |
||||
}; |
||||
|
||||
var HotSpotEl = function (hotspot, color) { |
||||
this.hotspot = hotspot; |
||||
this.element = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); |
||||
this.elStroke = 'rgb(' + color + ')'; |
||||
this.elFill = 'rgba(' + color + ', 0.5)'; |
||||
}; |
||||
HotSpotEl.prototype.render = function () { |
||||
return this; |
||||
}; |
||||
HotSpotEl.prototype.remove = function () { |
||||
if (!this.element) { |
||||
return; |
||||
} |
||||
|
||||
this.element.parentNode.removeChild(this.element); |
||||
this.hotspot = null; |
||||
}; |
||||
|
||||
var SquareEl = function (hotspot, color) { |
||||
HotSpotEl.call(this, hotspot, color); |
||||
|
||||
this.element = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); |
||||
this.element.setAttribute('stroke-width', 2); |
||||
this.element.setAttribute('stroke', this.elStroke); |
||||
this.element.setAttribute('fill', this.elFill); |
||||
}; |
||||
SquareEl.prototype = Object.create(HotSpotEl.prototype); |
||||
SquareEl.prototype.render = function () { |
||||
this.element.setAttribute('x', this.hotspot.x); |
||||
this.element.setAttribute('y', this.hotspot.y); |
||||
this.element.setAttribute('width', this.hotspot.width); |
||||
this.element.setAttribute('height', this.hotspot.height); |
||||
|
||||
return this.element; |
||||
}; |
||||
|
||||
var EllipseEl = function (hotspot, color) { |
||||
HotSpotEl.call(this, hotspot, color); |
||||
|
||||
this.element = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse'); |
||||
this.element.setAttribute('stroke-width', 2); |
||||
this.element.setAttribute('stroke', this.elStroke); |
||||
this.element.setAttribute('fill', this.elFill); |
||||
}; |
||||
EllipseEl.prototype = Object.create(HotSpotEl.prototype); |
||||
EllipseEl.prototype.render = function () { |
||||
this.element.setAttribute('cx', this.hotspot.centerX); |
||||
this.element.setAttribute('cy', this.hotspot.centerY); |
||||
this.element.setAttribute('rx', this.hotspot.radiusX); |
||||
this.element.setAttribute('ry', this.hotspot.radiusY); |
||||
|
||||
return this.element; |
||||
}; |
||||
|
||||
var PolygonEl = function (hotspot, color) { |
||||
HotSpotEl.call(this, hotspot, color); |
||||
|
||||
this.element = document.createElementNS('http://www.w3.org/2000/svg', 'polygon'); |
||||
this.element.setAttribute('stroke-width', 2); |
||||
this.element.setAttribute('stroke', this.elStroke); |
||||
this.element.setAttribute('fill', this.elFill); |
||||
}; |
||||
PolygonEl.prototype = Object.create(HotSpotEl.prototype); |
||||
PolygonEl.prototype.render = function () { |
||||
var pointsPaired = []; |
||||
|
||||
this.hotspot.points.forEach(function (point) { |
||||
pointsPaired.push(point.join(',')); |
||||
}); |
||||
|
||||
this.element.setAttribute( |
||||
'points', |
||||
pointsPaired.join(' ') |
||||
); |
||||
|
||||
return this.element; |
||||
}; |
||||
|
||||
var HotSpotSelectorEl = function (color, index, selectedValue) { |
||||
this.hotSpotIndex = parseInt(index); |
||||
this.elStroke = 'rgb(' + color + ')'; |
||||
this.elFill = 'rgba(' + color + ', 0.5)'; |
||||
|
||||
switch (selectedValue) { |
||||
case 'square': |
||||
default: |
||||
this.selectedValue = 'square'; |
||||
break; |
||||
|
||||
case 'circle': |
||||
this.selectedValue = 'ellipse'; |
||||
break; |
||||
|
||||
case 'poly': |
||||
this.selectedValue = 'polygon'; |
||||
break; |
||||
} |
||||
}; |
||||
HotSpotSelectorEl.prototype.render = function () { |
||||
var self = this; |
||||
|
||||
this.el = document.createElement('div'); |
||||
this.el.className = 'col-xs-6 col-sm-3 col-md-2'; |
||||
this.el.innerHTML = '\n\ |
||||
<div class="input-group">\n\ |
||||
<span class="input-group-addon" id="hotspot-' + this.hotSpotIndex + '">\n\ |
||||
<span class="fa fa-square fa-fw" data-hidden="true" style="color: ' + this.elStroke + '"></span>\n\ |
||||
</span>\n\ |
||||
<select class="form-control" aria-describedby="hotspot-' + this.hotSpotIndex + '">\n\ |
||||
<option value="">Select</option>\n\ |
||||
<option value="square">Square</option>\n\ |
||||
<option value="ellipse">Ellipse</option>\n\ |
||||
<option value="polygon">Polygon</option>\n\ |
||||
</select>\n\ |
||||
</div>\n\ |
||||
'; |
||||
|
||||
$(this.el).find('select').val(this.selectedValue); |
||||
|
||||
var selectShapeEvent = function (e) { |
||||
switch (this.value) { |
||||
case 'square': |
||||
//no break
|
||||
case 'ellipse': |
||||
//no break
|
||||
case 'polygon': |
||||
currentShapeType = this.value; |
||||
currentHotSpotIndex = self.hotSpotIndex; |
||||
break; |
||||
|
||||
default: |
||||
break; |
||||
} |
||||
}; |
||||
|
||||
$(this.el).on('click', selectShapeEvent); |
||||
$(this.el).find('select').on('change', selectShapeEvent); |
||||
|
||||
return this.el; |
||||
}; |
||||
|
||||
var colors = [ |
||||
'66, 113, 181', |
||||
'254, 142, 22', |
||||
'69, 199, 240', |
||||
'188, 214, 49', |
||||
'214, 49, 115', |
||||
'215, 215, 215', |
||||
'144, 175, 221', |
||||
'174, 134, 64', |
||||
'79, 146, 66', |
||||
'244, 235, 36', |
||||
'237, 32, 36', |
||||
'59, 59, 59', |
||||
'247, 189, 226' |
||||
]; |
||||
|
||||
var getPointOnImage = function (x, y) { |
||||
var pointerPosition = { |
||||
left: x + window.scrollX, |
||||
top: y + window.scrollY |
||||
}, |
||||
canvasOffset = { |
||||
x: canvas.getBoundingClientRect().x + window.scrollX, |
||||
y: canvas.getBoundingClientRect().y + window.scrollY |
||||
}; |
||||
|
||||
return { |
||||
x: Math.round(pointerPosition.left - canvasOffset.x), |
||||
y: Math.round(pointerPosition.top - canvasOffset.y) |
||||
}; |
||||
}; |
||||
|
||||
var startCanvas = function () { |
||||
var newHotSpotEl = null, |
||||
pressingShift = false; |
||||
|
||||
document.addEventListener('keydown', function (e) { |
||||
if (e.keyCode === 16) { |
||||
pressingShift = true; |
||||
} |
||||
}, false); |
||||
document.addEventListener('keyup', function (e) { |
||||
if (e.keyCode === 16) { |
||||
pressingShift = false; |
||||
} |
||||
}, false); |
||||
|
||||
canvas.addEventListener('click', function (e) { |
||||
e.preventDefault(); |
||||
}, false); |
||||
|
||||
container.addEventListener('dragstart', function (e) { |
||||
e.preventDefault(); |
||||
}, false); |
||||
container.addEventListener('click', function (e) { |
||||
if (shapes.length >= colors.length) { |
||||
return; |
||||
} |
||||
|
||||
newHotSpotEl = draw(newHotSpotEl, e.clientX, e.clientY, pressingShift); |
||||
|
||||
if (!newHotSpotEl) { |
||||
updateValues(); |
||||
} |
||||
}, false); |
||||
}; |
||||
|
||||
var draw = function (hotSpotEl, x, y, isPressingShift) { |
||||
var pointerPosition = getPointOnImage(x, y), |
||||
hotSpot = null; |
||||
|
||||
if (!hotSpotEl) { |
||||
switch (currentShapeType) { |
||||
case 'square': |
||||
//no break
|
||||
case 'ellipse': |
||||
if (currentShapeType === 'ellipse') { |
||||
hotSpot = new HotSpotEllipse(); |
||||
hotSpotEl = new EllipseEl(hotSpot, colors[currentHotSpotIndex]); |
||||
} else { |
||||
hotSpot = new HotSpotSquare(); |
||||
hotSpotEl = new SquareEl(hotSpot, colors[currentHotSpotIndex]); |
||||
} |
||||
|
||||
hotSpot.setStartPoint(pointerPosition.x, pointerPosition.y); |
||||
break; |
||||
|
||||
case 'polygon': |
||||
hotSpot = new HotSpotPolygon(); |
||||
hotSpotEl = new PolygonEl(hotSpot, colors[currentHotSpotIndex]); |
||||
|
||||
hotSpot.addPoint(pointerPosition.x, pointerPosition.y); |
||||
break; |
||||
} |
||||
|
||||
shapes[currentHotSpotIndex].remove(); |
||||
shapes.splice(currentHotSpotIndex, 1, hotSpotEl); |
||||
|
||||
canvas.appendChild(hotSpotEl.render()); |
||||
|
||||
return hotSpotEl; |
||||
} |
||||
|
||||
switch (currentShapeType) { |
||||
case 'square': |
||||
//no break
|
||||
case 'ellipse': |
||||
hotSpotEl.hotspot.setEndPoint(pointerPosition.x, pointerPosition.y); |
||||
hotSpotEl.render(); |
||||
|
||||
hotSpotEl = null; |
||||
break; |
||||
|
||||
case 'polygon': |
||||
$(container).find('#hotspot-alert').text('Keed pressed the SHIFT key and click the image to close the polygon'); |
||||
|
||||
hotSpotEl.hotspot.addPoint(pointerPosition.x, pointerPosition.y); |
||||
hotSpotEl.render(); |
||||
|
||||
if (isPressingShift) { |
||||
hotSpotEl = null; |
||||
$(container).find('#hotspot-alert').text(''); |
||||
} |
||||
break; |
||||
} |
||||
|
||||
return hotSpotEl; |
||||
}; |
||||
|
||||
var updateValues = function () { |
||||
var currentHotSpotEl = shapes[currentHotSpotIndex]; |
||||
|
||||
if (currentHotSpotIndex === undefined) { |
||||
return; |
||||
} |
||||
|
||||
if (currentHotSpotEl.hotspot instanceof HotSpotSquare) { |
||||
$('[name="hotspot_type[' + (currentHotSpotIndex + 1) + ']"]').val('square'); |
||||
} else if (currentHotSpotEl.hotspot instanceof HotSpotEllipse) { |
||||
$('[name="hotspot_type[' + (currentHotSpotIndex + 1) + ']"]').val('circle'); |
||||
} else if (currentHotSpotEl.hotspot instanceof HotSpotPolygon) { |
||||
$('[name="hotspot_type[' + (currentHotSpotIndex + 1) + ']"]').val('poly'); |
||||
} |
||||
|
||||
$('[name="hotspot_coordinates[' + (currentHotSpotIndex + 1) + ']"]').val( |
||||
currentHotSpotEl.hotspot.encode() |
||||
); |
||||
}; |
||||
|
||||
var loadHotSpots = function (hotSpotList) { |
||||
hotSpotList.forEach(function (hotSpotData, index) { |
||||
var hotSpot = null, |
||||
hotSpotEl = null, |
||||
color = colors[shapes.length]; |
||||
|
||||
switch (hotSpotData.type) { |
||||
case 'square': |
||||
hotSpot = new HotSpotSquare(); |
||||
hotSpotEl = new SquareEl(hotSpot, color); |
||||
|
||||
var coords = hotSpotData.coord.split('|'), |
||||
position = coords[0].split(';'), |
||||
x = parseInt(position[0]), |
||||
y = parseInt(position[1]), |
||||
width = parseInt(coords[1]), |
||||
height = parseInt(coords[2]); |
||||
|
||||
hotSpot.setStartPoint(x, y); |
||||
hotSpot.setEndPoint(x + width, y + height); |
||||
break; |
||||
case 'circle': |
||||
hotSpot = new HotSpotEllipse(); |
||||
hotSpotEl = new EllipseEl(hotSpot, color); |
||||
|
||||
var coords = hotSpotData.coord.split('|'), |
||||
position = coords[0].split(';'), |
||||
x = parseInt(position[0] - coords[1]), |
||||
y = parseInt(position[1] - coords[2]), |
||||
width = parseInt(coords[1]) * 2, |
||||
height = parseInt(coords[2]) * 2; |
||||
|
||||
hotSpot.setStartPoint(x, y); |
||||
hotSpot.setEndPoint(x + width, y + height); |
||||
break; |
||||
|
||||
case 'poly': |
||||
hotSpot = new HotSpotPolygon(); |
||||
hotSpotEl = new PolygonEl(hotSpot, color); |
||||
|
||||
hotSpotData.coord.split('|').forEach(function (point) { |
||||
var exis = point.split(';'); |
||||
|
||||
hotSpot.addPoint(exis[0], exis[1]); |
||||
}); |
||||
break; |
||||
} |
||||
|
||||
if (hotSpotEl) { |
||||
var hotSpotSelector = new HotSpotSelectorEl(color, index, hotSpotData.type); |
||||
|
||||
selectors.appendChild(hotSpotSelector.render()); |
||||
canvas.appendChild(hotSpotEl.render()); |
||||
shapes.push(hotSpotEl); |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
var container, canvas, selectors, currentShapeType, currentHotSpotIndex, shapes = []; |
||||
|
||||
return { |
||||
init: function (questionId, imageSrc) { |
||||
if (!questionId || !imageSrc) { |
||||
return; |
||||
} |
||||
|
||||
selectors = document.querySelector('#hotspot-selectors'); |
||||
container = document.querySelector('#hotspot-container'); |
||||
canvas = document.querySelector('#hotspot-container svg'); |
||||
currentShapeType = 'square'; |
||||
|
||||
var xhrImage = new $.Deferred(); |
||||
|
||||
var image = new Image(); |
||||
image.onload = function () { |
||||
xhrImage.resolve(this); |
||||
}; |
||||
image.onerror = function () { |
||||
xhrImage.reject(); |
||||
}; |
||||
image.src = imageSrc; |
||||
|
||||
var xhrHotSpots = $.get('/main/exercice/hotspot_actionscript_admin.as.php', { |
||||
modifyAnswers: parseInt(questionId) |
||||
}); |
||||
|
||||
$.when.apply($, [xhrImage, xhrHotSpots]).done(function (imageRequest, hotSpotsRequest) { |
||||
var imageSvg = document.createElementNS('http://www.w3.org/2000/svg', 'image'); |
||||
imageSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', imageRequest.src); |
||||
imageSvg.setAttribute('width', imageRequest.width); |
||||
imageSvg.setAttribute('height', imageRequest.height); |
||||
|
||||
container.style.width = imageRequest.width + 'px'; |
||||
canvas.setAttribute('viewBox', '0 0 ' + imageRequest.width + ' ' + imageRequest.height); |
||||
canvas.appendChild(imageSvg); |
||||
|
||||
loadHotSpots(hotSpotsRequest[0].hotspots); |
||||
startCanvas(); |
||||
}); |
||||
} |
||||
}; |
||||
})(); |
@ -0,0 +1,231 @@ |
||||
var HotSpotSolution = (function () { |
||||
var Answer = function () { |
||||
this.x = 0; |
||||
this.y = 0; |
||||
}; |
||||
|
||||
var HotSpot = function () { |
||||
this.id = 0; |
||||
this.name = ''; |
||||
}; |
||||
|
||||
var Square = function () { |
||||
HotSpot.call(this); |
||||
|
||||
this.x = 0, |
||||
this.y = 0, |
||||
this.width = 0, |
||||
this.height = 0; |
||||
}; |
||||
Square.prototype = Object.create(HotSpot.prototype); |
||||
|
||||
var Ellipse = function () { |
||||
HotSpot.call(this); |
||||
|
||||
this.centerX = 0; |
||||
this.centerY = 0; |
||||
this.radiusX = 0; |
||||
this.radiusY = 0; |
||||
}; |
||||
Ellipse.prototype = Object.create(HotSpot.prototype); |
||||
|
||||
var Polygon = function () { |
||||
HotSpot.call(this); |
||||
|
||||
this.points = []; |
||||
}; |
||||
Polygon.prototype = Object.create(HotSpot.prototype); |
||||
|
||||
var config, lang, hotSpots = [], answers = []; |
||||
|
||||
var CanvasSVG = function (image) { |
||||
var imageSvg = document.createElementNS('http://www.w3.org/2000/svg', 'image'); |
||||
imageSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'href', image.src); |
||||
imageSvg.setAttribute('width', image.width); |
||||
imageSvg.setAttribute('height', image.height); |
||||
|
||||
this.el = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); |
||||
this.el.setAttribute('version', '1.1'); |
||||
this.el.setAttribute('viewBox', '0 0 ' + image.width + ' ' + image.height); |
||||
this.el.appendChild(imageSvg); |
||||
}; |
||||
CanvasSVG.prototype.addHotSpot = function (hotSpot) { |
||||
var hotSpotSVG = null; |
||||
|
||||
if (hotSpot instanceof Square) { |
||||
hotSpotSVG = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); |
||||
hotSpotSVG.setAttribute('x', hotSpot.x); |
||||
hotSpotSVG.setAttribute('y', hotSpot.y); |
||||
hotSpotSVG.setAttribute('width', hotSpot.width); |
||||
hotSpotSVG.setAttribute('height', hotSpot.height); |
||||
} else if (hotSpot instanceof Ellipse) { |
||||
hotSpotSVG = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse'); |
||||
hotSpotSVG.setAttribute('cx', hotSpot.centerX); |
||||
hotSpotSVG.setAttribute('cy', hotSpot.centerY); |
||||
hotSpotSVG.setAttribute('rx', hotSpot.radiusX); |
||||
hotSpotSVG.setAttribute('ry', hotSpot.radiusY); |
||||
} else if (hotSpot instanceof Polygon) { |
||||
var pointsPaired = []; |
||||
|
||||
hotSpot.points.forEach(function (point) { |
||||
pointsPaired.push(point.join(',')); |
||||
}); |
||||
|
||||
hotSpotSVG = document.createElementNS('http://www.w3.org/2000/svg', 'polygon'); |
||||
hotSpotSVG.setAttribute( |
||||
'points', |
||||
pointsPaired.join(' ') |
||||
); |
||||
} |
||||
|
||||
if (!hotSpotSVG) { |
||||
return; |
||||
} |
||||
|
||||
var color = colors[hotSpots.length - 1]; |
||||
|
||||
hotSpotSVG.setAttribute('stroke-width', 2); |
||||
hotSpotSVG.setAttribute('stroke', 'rgb(' + color + ')'); |
||||
hotSpotSVG.setAttribute('fill', 'rgba(' + color + ', 0.75)'); |
||||
|
||||
this.el.appendChild(hotSpotSVG); |
||||
}; |
||||
CanvasSVG.prototype.addAnswer = function (answer) { |
||||
var pointSVG = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); |
||||
pointSVG.setAttribute('cx', answer.x); |
||||
pointSVG.setAttribute('cy', answer.y); |
||||
pointSVG.setAttribute('r', 15); |
||||
pointSVG.setAttribute('fill', '#00677C'); |
||||
|
||||
var textSVG = document.createElementNS('http://www.w3.org/2000/svg', 'text'); |
||||
textSVG.setAttribute('x', answer.x); |
||||
textSVG.setAttribute('y', answer.y); |
||||
textSVG.setAttribute('dy', 5); |
||||
textSVG.setAttribute('font-family', 'sans-serif'); |
||||
textSVG.setAttribute('text-anchor', 'middle'); |
||||
textSVG.setAttribute('fill', 'white'); |
||||
textSVG.textContent = answers.length; |
||||
|
||||
this.el.appendChild(pointSVG); |
||||
this.el.appendChild(textSVG); |
||||
}; |
||||
|
||||
var decodeHotSpot = function (hotSpotInfo) { |
||||
var hotSpot = null, |
||||
coords = hotSpotInfo.coord.split('|'); |
||||
|
||||
switch (hotSpotInfo.type) { |
||||
case 'square': |
||||
var position = coords[0].split(';'); |
||||
|
||||
hotSpot = new Square(); |
||||
hotSpot.x = parseInt(position[0]); |
||||
hotSpot.y = parseInt(position[1]); |
||||
hotSpot.width = parseInt(coords[1]); |
||||
hotSpot.height = parseInt(coords[2]); |
||||
break; |
||||
case 'circle': |
||||
var center = coords[0].split(';'); |
||||
|
||||
hotSpot = new Ellipse(); |
||||
hotSpot.centerX = parseInt(center[0]); |
||||
hotSpot.centerY = parseInt(center[1]); |
||||
hotSpot.radiusX = parseInt(coords[1]); |
||||
hotSpot.radiusY = parseInt(coords[2]); |
||||
break; |
||||
case 'poly': |
||||
hotSpot = new Polygon(); |
||||
|
||||
coords.forEach(function (pairedCoord) { |
||||
var coord = pairedCoord.split(';'); |
||||
|
||||
hotSpot.points.push([ |
||||
parseInt(coord[0]), |
||||
parseInt(coord[1]) |
||||
]); |
||||
}); |
||||
break; |
||||
} |
||||
|
||||
return hotSpot; |
||||
}; |
||||
|
||||
var decodeAnswer = function (answerInfo) { |
||||
var answer = null, |
||||
coords = answerInfo.split(';'); |
||||
|
||||
answer = new Answer(); |
||||
answer.x = coords[0]; |
||||
answer.y = coords[1]; |
||||
|
||||
return answer; |
||||
}; |
||||
|
||||
var colors = [ |
||||
'66, 113, 181', |
||||
'254, 142, 22', |
||||
'69, 199, 240', |
||||
'188, 214, 49', |
||||
'214, 49, 115', |
||||
'215, 215, 215', |
||||
'144, 175, 221', |
||||
'174, 134, 64', |
||||
'79, 146, 66', |
||||
'244, 235, 36', |
||||
'237, 32, 36', |
||||
'59, 59, 59' |
||||
]; |
||||
|
||||
var startAnswer = function (hotSpotAnswerInfo) { |
||||
var image = new Image(); |
||||
image.onload = function () { |
||||
var canvasSVG = new CanvasSVG(this); |
||||
|
||||
hotSpotAnswerInfo.hotspots.forEach(function (hotSpotInfo) { |
||||
var hotSpot = decodeHotSpot(hotSpotInfo); |
||||
|
||||
if (!hotSpot) { |
||||
return; |
||||
} |
||||
|
||||
hotSpots.push(hotSpot); |
||||
canvasSVG.addHotSpot(hotSpot); |
||||
}); |
||||
|
||||
hotSpotAnswerInfo.answers.forEach(function (answerInfo) { |
||||
var answer = decodeAnswer(answerInfo); |
||||
|
||||
answers.push(answer); |
||||
canvasSVG.addAnswer(answer); |
||||
}); |
||||
|
||||
$(config.selector) |
||||
.css('width', this.width) |
||||
.append(canvasSVG.el); |
||||
}; |
||||
image.src = hotSpotAnswerInfo.image; |
||||
|
||||
lang = hotSpotAnswerInfo.lang; |
||||
}; |
||||
|
||||
return { |
||||
init: function (settings) { |
||||
config = $.extend({ |
||||
questionId: 0, |
||||
exerciseId: 0, |
||||
selector: '' |
||||
}, settings); |
||||
|
||||
if (!config.questionId || !config.selector) { |
||||
return; |
||||
} |
||||
|
||||
var xhrHotSpotAnswers = $.getJSON('/main/exercice/hotspot_answers.as.php', { |
||||
modifyAnswers: parseInt(config.questionId), |
||||
exe_id: parseInt(config.exerciseId) |
||||
}); |
||||
|
||||
$.when(xhrHotSpotAnswers).done(startAnswer); |
||||
} |
||||
}; |
||||
})(); |
@ -0,0 +1,269 @@ |
||||
var HotSpotUser = (function () { |
||||
var Answer = function () { |
||||
this.x = 0; |
||||
this.y = 0; |
||||
}; |
||||
|
||||
var HotSpot = function () { |
||||
this.id = 0; |
||||
this.name = ''; |
||||
}; |
||||
HotSpot.prototype.checkPoint = function (x, y) { |
||||
return false; |
||||
}; |
||||
|
||||
var Square = function () { |
||||
HotSpot.call(this); |
||||
|
||||
this.x = 0, |
||||
this.y = 0, |
||||
this.width = 0, |
||||
this.height = 0; |
||||
}; |
||||
Square.prototype = Object.create(HotSpot.prototype); |
||||
Square.prototype.checkPoint = function (x, y) { |
||||
var left = this.x, |
||||
right = this.x + this.width, |
||||
top = this.y, |
||||
bottom = this.y + this.height; |
||||
|
||||
var xIsValid = x >= left && x <= right, |
||||
yIsValid = y >= top && y <= bottom; |
||||
|
||||
return xIsValid && yIsValid; |
||||
}; |
||||
|
||||
var Ellipse = function () { |
||||
HotSpot.call(this); |
||||
|
||||
this.centerX = 0; |
||||
this.centerY = 0; |
||||
this.radiusX = 0; |
||||
this.radiusY = 0; |
||||
}; |
||||
Ellipse.prototype = Object.create(HotSpot.prototype); |
||||
Ellipse.prototype.checkPoint = function (x, y) { |
||||
var dX = x - this.centerX, |
||||
dY = y - this.centerY; |
||||
|
||||
return Math.pow(dX, 2) / Math.pow(this.radiusX, 2) + Math.pow(dY, 2) / Math.pow(this.radiusY, 2) <= 1; |
||||
}; |
||||
|
||||
var Polygon = function () { |
||||
HotSpot.call(this); |
||||
|
||||
this.points = []; |
||||
}; |
||||
Polygon.prototype = Object.create(HotSpot.prototype); |
||||
Polygon.prototype.checkPoint = function (x, y) { |
||||
var isInside = false; |
||||
|
||||
for (var i = 0, j = this.points.length - 1; i < this.points.length; j = i++) { |
||||
var xi = this.points[i][0], |
||||
yi = this.points[i][1], |
||||
xj = this.points[j][0], |
||||
yj = this.points[j][1]; |
||||
|
||||
var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); |
||||
|
||||
if (intersect) { |
||||
isInside = !isInside; |
||||
} |
||||
} |
||||
|
||||
return isInside; |
||||
}; |
||||
|
||||
var CanvasSVG = function (image) { |
||||
var imageSvg = document.createElementNS('http://www.w3.org/2000/svg', 'image'); |
||||
imageSvg.setAttributeNS('http://www.w3.org/1999/xlink', 'href', image.src); |
||||
imageSvg.setAttribute('width', image.width); |
||||
imageSvg.setAttribute('height', image.height); |
||||
|
||||
this.el = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); |
||||
this.el.setAttribute('version', '1.1'); |
||||
this.el.setAttribute('viewBox', '0 0 ' + image.width + ' ' + image.height); |
||||
this.el.appendChild(imageSvg); |
||||
|
||||
this.messagesEl = document.createElement('div'); |
||||
}; |
||||
CanvasSVG.prototype.setEvents = function () { |
||||
var self = this; |
||||
|
||||
var getPointOnImage = function (x, y) { |
||||
var pointerPosition = { |
||||
left: x + window.scrollX, |
||||
top: y + window.scrollY |
||||
}, |
||||
canvasOffset = { |
||||
x: self.el.getBoundingClientRect().x + window.scrollX, |
||||
y: self.el.getBoundingClientRect().y + window.scrollY |
||||
}; |
||||
|
||||
return { |
||||
x: Math.round(pointerPosition.left - canvasOffset.x), |
||||
y: Math.round(pointerPosition.top - canvasOffset.y) |
||||
}; |
||||
}; |
||||
|
||||
this.el.addEventListener('dragstart', function (e) { |
||||
e.preventDefault(); |
||||
}, false); |
||||
this.el.addEventListener('click', function (e) { |
||||
e.preventDefault(); |
||||
|
||||
if (answers.length >= hotSpots.length) { |
||||
return; |
||||
} |
||||
|
||||
var point = getPointOnImage(e.clientX, e.clientY); |
||||
|
||||
var answer = new Answer(); |
||||
answer.x = point.x; |
||||
answer.y = point.y; |
||||
|
||||
answers.push(answer); |
||||
self.addAnswer(answer); |
||||
|
||||
if (answers.length === hotSpots.length) { |
||||
self.messagesEl.textContent = lang.ExeFinished; |
||||
|
||||
return; |
||||
} |
||||
|
||||
self.messagesEl.textContent = lang.NextAnswer + ' ' + hotSpots[answers.length].name; |
||||
}); |
||||
}; |
||||
CanvasSVG.prototype.addAnswer = function (answer) { |
||||
var pointSVG = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); |
||||
pointSVG.setAttribute('cx', answer.x); |
||||
pointSVG.setAttribute('cy', answer.y); |
||||
pointSVG.setAttribute('r', 15); |
||||
pointSVG.setAttribute('fill', '#00677C'); |
||||
|
||||
var textSVG = document.createElementNS('http://www.w3.org/2000/svg', 'text'); |
||||
textSVG.setAttribute('x', answer.x); |
||||
textSVG.setAttribute('y', answer.y); |
||||
textSVG.setAttribute('dy', 5); |
||||
textSVG.setAttribute('font-family', 'sans-serif'); |
||||
textSVG.setAttribute('text-anchor', 'middle'); |
||||
textSVG.setAttribute('fill', 'white'); |
||||
textSVG.textContent = answers.length; |
||||
|
||||
this.el.appendChild(pointSVG); |
||||
this.el.appendChild(textSVG); |
||||
|
||||
var hotSpot = hotSpots[answers.length - 1]; |
||||
|
||||
var hotspotTxt = document.createElement('input'); |
||||
hotspotTxt.type = 'hidden'; |
||||
hotspotTxt.name = 'hotspot[' + config.questionId + '][' + hotSpot.id + ']'; |
||||
hotspotTxt.value = [answer.x, answer.y].join(';'); |
||||
|
||||
var choiceTxt = document.createElement('input'); |
||||
choiceTxt.type = 'hidden'; |
||||
choiceTxt.name = 'choice[' + config.questionId + '][' + hotSpot.id + ']'; |
||||
choiceTxt.value = hotSpot.checkPoint(answer.x, answer.y) ? 1 : 0; |
||||
|
||||
this.el.parentNode.appendChild(hotspotTxt); |
||||
this.el.parentNode.appendChild(choiceTxt); |
||||
}; |
||||
CanvasSVG.prototype.startMessagesPanel = function () { |
||||
this.messagesEl.textContent = lang.NextAnswer + ' ' + hotSpots[0].name; |
||||
|
||||
this.el.parentNode.parentNode.appendChild(this.messagesEl); |
||||
}; |
||||
|
||||
var decodeHotSpot = function (hotSpotInfo) { |
||||
var hotSpot = null, |
||||
coords = hotSpotInfo.coord.split('|'); |
||||
|
||||
switch (hotSpotInfo.type) { |
||||
case 'square': |
||||
var position = coords[0].split(';'); |
||||
|
||||
hotSpot = new Square(); |
||||
hotSpot.x = parseInt(position[0]); |
||||
hotSpot.y = parseInt(position[1]); |
||||
hotSpot.width = parseInt(coords[1]); |
||||
hotSpot.height = parseInt(coords[2]); |
||||
break; |
||||
case 'circle': |
||||
var center = coords[0].split(';'); |
||||
|
||||
hotSpot = new Ellipse(); |
||||
hotSpot.centerX = parseInt(center[0]); |
||||
hotSpot.centerY = parseInt(center[1]); |
||||
hotSpot.radiusX = parseInt(coords[1]); |
||||
hotSpot.radiusY = parseInt(coords[2]); |
||||
break; |
||||
case 'poly': |
||||
hotSpot = new Polygon(); |
||||
|
||||
coords.forEach(function (pairedCoord) { |
||||
var coord = pairedCoord.split(';'); |
||||
|
||||
hotSpot.points.push([ |
||||
parseInt(coord[0]), |
||||
parseInt(coord[1]) |
||||
]); |
||||
}); |
||||
break; |
||||
} |
||||
|
||||
if (hotSpot) { |
||||
hotSpot.id = parseInt(hotSpotInfo.id); |
||||
hotSpot.name = hotSpotInfo.answer; |
||||
} |
||||
|
||||
return hotSpot; |
||||
}; |
||||
|
||||
var config, lang, hotSpots = [], answers = []; |
||||
|
||||
var startQuestion = function (hotSpotQuestionInfo) { |
||||
var image = new Image(); |
||||
image.onload = function () { |
||||
var canvasSVG = new CanvasSVG(this); |
||||
|
||||
hotSpotQuestionInfo.hotspots.forEach(function (hotSpotInfo) { |
||||
var hotSpot = decodeHotSpot(hotSpotInfo); |
||||
|
||||
if (!hotSpot) { |
||||
return; |
||||
} |
||||
|
||||
hotSpots.push(hotSpot); |
||||
}); |
||||
|
||||
$(config.selector) |
||||
.css('width', this.width) |
||||
.append(canvasSVG.el); |
||||
|
||||
canvasSVG.setEvents(); |
||||
canvasSVG.startMessagesPanel(); |
||||
}; |
||||
image.src = hotSpotQuestionInfo.image; |
||||
|
||||
lang = hotSpotQuestionInfo.lang; |
||||
}; |
||||
|
||||
return { |
||||
init: function (settings) { |
||||
config = $.extend({ |
||||
questionId: 0, |
||||
selector: '' |
||||
}, settings); |
||||
|
||||
if (!config.questionId || !config.selector) { |
||||
return; |
||||
} |
||||
|
||||
var xhrHotSpotQuestion = $.getJSON('/main/exercice/hotspot_actionscript.as.php', { |
||||
modifyAnswers: parseInt(config.questionId) |
||||
}); |
||||
|
||||
$.when(xhrHotSpotQuestion).done(startQuestion); |
||||
}
|
||||
}; |
||||
})(); |
Loading…
Reference in new issue