|
|
|
|
|
(function($) { |
|
|
|
|
|
$.fn.annotateImage = function(options) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var opts = $.extend({}, $.fn.annotateImage.defaults, options); |
|
|
var image = this; |
|
|
|
|
|
this.image = this; |
|
|
this.mode = 'view'; |
|
|
|
|
|
|
|
|
this.getUrl = opts.getUrl; |
|
|
this.saveUrl = opts.saveUrl; |
|
|
this.deleteUrl = opts.deleteUrl; |
|
|
this.editable = opts.editable; |
|
|
this.useAjax = opts.useAjax; |
|
|
this.notes = opts.notes; |
|
|
|
|
|
|
|
|
this.canvas = $('<div class="image-annotate-canvas"><div class="image-annotate-view"></div><div class="image-annotate-edit"><div class="image-annotate-edit-area"></div></div></div>'); |
|
|
this.canvas.children('.image-annotate-edit').hide(); |
|
|
this.canvas.children('.image-annotate-view').hide(); |
|
|
this.image.after(this.canvas); |
|
|
|
|
|
|
|
|
this.canvas.height(this.height()); |
|
|
this.canvas.width(this.width()); |
|
|
this.canvas.css('background-image', 'url("' + this.attr('src') + '")'); |
|
|
this.canvas.children('.image-annotate-view, .image-annotate-edit').height(this.height()); |
|
|
this.canvas.children('.image-annotate-view, .image-annotate-edit').width(this.width()); |
|
|
|
|
|
|
|
|
this.canvas.hover(function() { |
|
|
if ($(this).children('.image-annotate-edit').css('display') == 'none') { |
|
|
$(this).children('.image-annotate-view').show(); |
|
|
} |
|
|
}, function() { |
|
|
$(this).children('.image-annotate-view').hide(); |
|
|
}); |
|
|
|
|
|
this.canvas.children('.image-annotate-view').hover(function() { |
|
|
$(this).show(); |
|
|
}, function() { |
|
|
$(this).hide(); |
|
|
}); |
|
|
|
|
|
|
|
|
if (this.useAjax) { |
|
|
$.fn.annotateImage.ajaxLoad(this); |
|
|
} else { |
|
|
$.fn.annotateImage.load(this); |
|
|
} |
|
|
|
|
|
|
|
|
if (this.editable) { |
|
|
this.button = $('<a class="image-annotate-add" id="image-annotate-add" href="#">Add Note</a>'); |
|
|
this.button.click(function() { |
|
|
$.fn.annotateImage.add(image); |
|
|
}); |
|
|
this.canvas.after(this.button); |
|
|
} |
|
|
|
|
|
|
|
|
this.hide(); |
|
|
|
|
|
return this; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$.fn.annotateImage.defaults = { |
|
|
getUrl: 'your-get.rails', |
|
|
saveUrl: 'your-save.rails', |
|
|
deleteUrl: 'your-delete.rails', |
|
|
editable: true, |
|
|
useAjax: true, |
|
|
notes: new Array() |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.clear = function(image) { |
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < image.notes.length; i++) { |
|
|
image.notes[image.notes[i]].destroy(); |
|
|
} |
|
|
image.notes = new Array(); |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.ajaxLoad = function(image) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$.getJSON(image.getUrl + '?ticks=' + $.fn.annotateImage.getTicks(), function(data) { |
|
|
image.notes = data; |
|
|
$.fn.annotateImage.load(image); |
|
|
}); |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.load = function(image) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < image.notes.length; i++) { |
|
|
image.notes[image.notes[i]] = new $.fn.annotateView(image, image.notes[i]); |
|
|
} |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.getTicks = function() { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var now = new Date(); |
|
|
return now.getTime(); |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.add = function(image) { |
|
|
|
|
|
|
|
|
|
|
|
if (image.mode == 'view') { |
|
|
image.mode = 'edit'; |
|
|
|
|
|
|
|
|
var editable = new $.fn.annotateEdit(image); |
|
|
|
|
|
$.fn.annotateImage.createSaveButton(editable, image); |
|
|
$.fn.annotateImage.createCancelButton(editable, image); |
|
|
} |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.createSaveButton = function(editable, image, note) { |
|
|
|
|
|
|
|
|
|
|
|
var ok = $('<a class="image-annotate-edit-ok">OK</a>'); |
|
|
|
|
|
ok.click(function() { |
|
|
var form = $('#image-annotate-edit-form form'); |
|
|
var text = $('#image-annotate-text').val(); |
|
|
$.fn.annotateImage.appendPosition(form, editable) |
|
|
image.mode = 'view'; |
|
|
|
|
|
|
|
|
if (image.useAjax) { |
|
|
$.ajax({ |
|
|
url: image.saveUrl, |
|
|
data: form.serialize(), |
|
|
error: function(e) { alert("An error occured saving that note.") }, |
|
|
success: function(data) { |
|
|
if (data.annotation_id != undefined) { |
|
|
editable.note.id = data.annotation_id; |
|
|
} |
|
|
}, |
|
|
dataType: "json" |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
if (note) { |
|
|
note.resetPosition(editable, text); |
|
|
} else { |
|
|
editable.note.editable = true; |
|
|
note = new $.fn.annotateView(image, editable.note) |
|
|
note.resetPosition(editable, text); |
|
|
image.notes.push(editable.note); |
|
|
} |
|
|
|
|
|
editable.destroy(); |
|
|
}); |
|
|
editable.form.append(ok); |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.createCancelButton = function(editable, image) { |
|
|
|
|
|
|
|
|
|
|
|
var cancel = $('<a class="image-annotate-edit-close">Cancel</a>'); |
|
|
cancel.click(function() { |
|
|
editable.destroy(); |
|
|
image.mode = 'view'; |
|
|
}); |
|
|
editable.form.append(cancel); |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.saveAsHtml = function(image, target) { |
|
|
var element = $(target); |
|
|
var html = ""; |
|
|
for (var i = 0; i < image.notes.length; i++) { |
|
|
html += $.fn.annotateImage.createHiddenField("text_" + i, image.notes[i].text); |
|
|
html += $.fn.annotateImage.createHiddenField("top_" + i, image.notes[i].top); |
|
|
html += $.fn.annotateImage.createHiddenField("left_" + i, image.notes[i].left); |
|
|
html += $.fn.annotateImage.createHiddenField("height_" + i, image.notes[i].height); |
|
|
html += $.fn.annotateImage.createHiddenField("width_" + i, image.notes[i].width); |
|
|
} |
|
|
element.html(html); |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.createHiddenField = function(name, value) { |
|
|
return '<input type="hidden" name="' + name + '" value="' + value + '" /><br />'; |
|
|
}; |
|
|
|
|
|
$.fn.annotateEdit = function(image, note) { |
|
|
|
|
|
|
|
|
|
|
|
this.image = image; |
|
|
|
|
|
if (note) { |
|
|
this.note = note; |
|
|
} else { |
|
|
var newNote = new Object(); |
|
|
newNote.id = "new"; |
|
|
newNote.top = 30; |
|
|
newNote.left = 30; |
|
|
newNote.width = 30; |
|
|
newNote.height = 30; |
|
|
newNote.text = ""; |
|
|
this.note = newNote; |
|
|
} |
|
|
|
|
|
|
|
|
var area = image.canvas.children('.image-annotate-edit').children('.image-annotate-edit-area'); |
|
|
this.area = area; |
|
|
this.area.css('height', this.note.height + 'px'); |
|
|
this.area.css('width', this.note.width + 'px'); |
|
|
this.area.css('left', this.note.left + 'px'); |
|
|
this.area.css('top', this.note.top + 'px'); |
|
|
|
|
|
|
|
|
image.canvas.children('.image-annotate-view').hide(); |
|
|
image.canvas.children('.image-annotate-edit').show(); |
|
|
|
|
|
|
|
|
var form = $('<div id="image-annotate-edit-form"><form><textarea id="image-annotate-text" name="text" rows="3" cols="30">' + this.note.text + '</textarea></form></div>'); |
|
|
this.form = form; |
|
|
|
|
|
$('body').append(this.form); |
|
|
this.form.css('left', this.area.offset().left + 'px'); |
|
|
this.form.css('top', (parseInt(this.area.offset().top) + parseInt(this.area.height()) + 7) + 'px'); |
|
|
|
|
|
|
|
|
|
|
|
area.resizable({ |
|
|
handles: 'all', |
|
|
|
|
|
stop: function(e, ui) { |
|
|
form.css('left', area.offset().left + 'px'); |
|
|
form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px'); |
|
|
} |
|
|
}) |
|
|
.draggable({ |
|
|
containment: image.canvas, |
|
|
drag: function(e, ui) { |
|
|
form.css('left', area.offset().left + 'px'); |
|
|
form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px'); |
|
|
}, |
|
|
stop: function(e, ui) { |
|
|
form.css('left', area.offset().left + 'px'); |
|
|
form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px'); |
|
|
} |
|
|
}); |
|
|
return this; |
|
|
}; |
|
|
|
|
|
$.fn.annotateEdit.prototype.destroy = function() { |
|
|
|
|
|
|
|
|
|
|
|
this.image.canvas.children('.image-annotate-edit').hide(); |
|
|
this.area.resizable('destroy'); |
|
|
this.area.draggable('destroy'); |
|
|
this.area.css('height', ''); |
|
|
this.area.css('width', ''); |
|
|
this.area.css('left', ''); |
|
|
this.area.css('top', ''); |
|
|
this.form.remove(); |
|
|
} |
|
|
|
|
|
$.fn.annotateView = function(image, note) { |
|
|
|
|
|
|
|
|
|
|
|
this.image = image; |
|
|
|
|
|
this.note = note; |
|
|
|
|
|
this.editable = (note.editable && image.editable); |
|
|
|
|
|
|
|
|
this.area = $('<div class="image-annotate-area' + (this.editable ? ' image-annotate-area-editable' : '') + '"><div></div></div>'); |
|
|
image.canvas.children('.image-annotate-view').prepend(this.area); |
|
|
|
|
|
|
|
|
this.form = $('<div class="image-annotate-note">' + note.text + '</div>'); |
|
|
this.form.hide(); |
|
|
image.canvas.children('.image-annotate-view').append(this.form); |
|
|
this.form.children('span.actions').hide(); |
|
|
|
|
|
|
|
|
this.setPosition(); |
|
|
|
|
|
|
|
|
var annotation = this; |
|
|
this.area.hover(function() { |
|
|
annotation.show(); |
|
|
}, function() { |
|
|
annotation.hide(); |
|
|
}); |
|
|
|
|
|
|
|
|
if (this.editable) { |
|
|
var form = this; |
|
|
this.area.click(function() { |
|
|
form.edit(); |
|
|
}); |
|
|
} |
|
|
}; |
|
|
|
|
|
$.fn.annotateView.prototype.setPosition = function() { |
|
|
|
|
|
|
|
|
|
|
|
this.area.children('div').height((parseInt(this.note.height) - 2) + 'px'); |
|
|
this.area.children('div').width((parseInt(this.note.width) - 2) + 'px'); |
|
|
this.area.css('left', (this.note.left) + 'px'); |
|
|
this.area.css('top', (this.note.top) + 'px'); |
|
|
this.form.css('left', (this.note.left) + 'px'); |
|
|
this.form.css('top', (parseInt(this.note.top) + parseInt(this.note.height) + 7) + 'px'); |
|
|
}; |
|
|
|
|
|
$.fn.annotateView.prototype.show = function() { |
|
|
|
|
|
|
|
|
|
|
|
this.form.fadeIn(250); |
|
|
if (!this.editable) { |
|
|
this.area.addClass('image-annotate-area-hover'); |
|
|
} else { |
|
|
this.area.addClass('image-annotate-area-editable-hover'); |
|
|
} |
|
|
}; |
|
|
|
|
|
$.fn.annotateView.prototype.hide = function() { |
|
|
|
|
|
|
|
|
|
|
|
this.form.fadeOut(250); |
|
|
this.area.removeClass('image-annotate-area-hover'); |
|
|
this.area.removeClass('image-annotate-area-editable-hover'); |
|
|
}; |
|
|
|
|
|
$.fn.annotateView.prototype.destroy = function() { |
|
|
|
|
|
|
|
|
|
|
|
this.area.remove(); |
|
|
this.form.remove(); |
|
|
} |
|
|
|
|
|
$.fn.annotateView.prototype.edit = function() { |
|
|
|
|
|
|
|
|
|
|
|
if (this.image.mode == 'view') { |
|
|
this.image.mode = 'edit'; |
|
|
var annotation = this; |
|
|
|
|
|
|
|
|
var editable = new $.fn.annotateEdit(this.image, this.note); |
|
|
|
|
|
$.fn.annotateImage.createSaveButton(editable, this.image, annotation); |
|
|
|
|
|
|
|
|
var del = $('<a class="image-annotate-edit-delete">Delete</a>'); |
|
|
del.click(function() { |
|
|
var form = $('#image-annotate-edit-form form'); |
|
|
|
|
|
$.fn.annotateImage.appendPosition(form, editable) |
|
|
|
|
|
if (annotation.image.useAjax) { |
|
|
$.ajax({ |
|
|
url: annotation.image.deleteUrl, |
|
|
data: form.serialize(), |
|
|
error: function(e) { alert("An error occured deleting that note.") } |
|
|
}); |
|
|
} |
|
|
|
|
|
annotation.image.mode = 'view'; |
|
|
editable.destroy(); |
|
|
annotation.destroy(); |
|
|
}); |
|
|
editable.form.append(del); |
|
|
|
|
|
$.fn.annotateImage.createCancelButton(editable, this.image); |
|
|
} |
|
|
}; |
|
|
|
|
|
$.fn.annotateImage.appendPosition = function(form, editable) { |
|
|
|
|
|
|
|
|
|
|
|
var areaFields = $('<input type="hidden" value="' + editable.area.height() + '" name="height"/>' + |
|
|
'<input type="hidden" value="' + editable.area.width() + '" name="width"/>' + |
|
|
'<input type="hidden" value="' + editable.area.position().top + '" name="top"/>' + |
|
|
'<input type="hidden" value="' + editable.area.position().left + '" name="left"/>' + |
|
|
'<input type="hidden" value="' + editable.note.id + '" name="id"/>'); |
|
|
form.append(areaFields); |
|
|
} |
|
|
|
|
|
$.fn.annotateView.prototype.resetPosition = function(editable, text) { |
|
|
|
|
|
|
|
|
|
|
|
this.form.html(text); |
|
|
this.form.hide(); |
|
|
|
|
|
|
|
|
this.area.children('div').height(editable.area.height() + 'px'); |
|
|
this.area.children('div').width((editable.area.width() - 2) + 'px'); |
|
|
this.area.css('left', (editable.area.position().left) + 'px'); |
|
|
this.area.css('top', (editable.area.position().top) + 'px'); |
|
|
this.form.css('left', (editable.area.position().left) + 'px'); |
|
|
this.form.css('top', (parseInt(editable.area.position().top) + parseInt(editable.area.height()) + 7) + 'px'); |
|
|
|
|
|
|
|
|
this.note.top = editable.area.position().top; |
|
|
this.note.left = editable.area.position().left; |
|
|
this.note.height = editable.area.height(); |
|
|
this.note.width = editable.area.width(); |
|
|
this.note.text = text; |
|
|
this.note.id = editable.note.id; |
|
|
this.editable = true; |
|
|
}; |
|
|
|
|
|
})(jQuery); |