Skip to content

Instantly share code, notes, and snippets.

@mapmeld
Created April 19, 2012 06:04
Show Gist options
  • Save mapmeld/2419014 to your computer and use it in GitHub Desktop.
Save mapmeld/2419014 to your computer and use it in GitHub Desktop.
Red Pen: experimental auto-marker for FieldPapers.org
/*
Red Pen turns red (and blue!) dots on Field Papers tiles into markers automatically
Tested with Sharpie and PaperMate ballpoint pens
Write a description to save the marker
I don't understand the server-side installation or the QR-scanning, so I'm using a bookmarklet
Client-side HTML5 Canvas for tile inspection
*/
// collect the most zoomed-in tiles from the scan
var zoomimgs = document.getElementsByTagName("img");
var maxzoom = 0;
var maxzoomitems = [ ];
for(var z=0; z<zoomimgs.length; z++){
if(zoomimgs[z].src.split('/').length > 7){
if(zoomimgs[z].src.split('/')[4] == "scans"){
if(zoomimgs[z].src.split('/')[6] > maxzoom){
maxzoom = zoomimgs[z].src.split('/')[6];
maxzoomitems = [ zoomimgs[z] ];
}
else if(zoomimgs[z].src.split('/')[6] == maxzoom){
maxzoomitems.push( zoomimgs[z] );
}
}
}
}
var tileCanvas = document.createElement("canvas");
tileCanvas.width = 256;
tileCanvas.height = 256;
// dev: spy on the process
tileCanvas.position = "fixed";
tileCanvas.top = 0;
tileCanvas.left = 0;
document.body.appendChild(tileCanvas);
var tileCtx = tileCanvas.getContext("2d");
var reddots = [ ];
var bluedots = [ ];
for(var mz=0;mz<maxzoomitems.length;mz++){
tileCtx.drawImage(maxzoomitems[mz], 0, 0, 256, 256);
var imgData = tileCtx.getImageData(0, 0, 256, 256);
for(var x=0; x<256; x++){
for(var y=0; y<256; y++){
//console.log(x + "," + y);
var r = imgData.data[y*4*256+x*4];
var g = imgData.data[y*4*256+x*4+1];
var b = imgData.data[y*4*256+x*4+2];
var a = imgData.data[y*4*256+x*4+3];
if((r > 160 && g < 80 & b < 80) || (r > 150 && g < 70 & b < 70) || (r > 110 && g < 60 & b < 60) || ( r > 140 && g < 90 && b < 110 )){
//imgData.data[y*4*256+x*4+2] = 250;
//console.log("red");
var transform = maxzoomitems[mz].style.webkitTransform.split(",");
reddots.push([ (transform[12] * 1 + x) , (transform[13] * 1 + y) ]);
//console.log( (transform[12] * 1 + x) + "," + (transform[13] * 1 + y) );
}
else if( ( r < 90 && g < 110 & b > 150 ) || (r < 50 && g < 50 && b > 80) ){
// blue dot?
var transform = maxzoomitems[mz].style.webkitTransform.split(",");
bluedots.push([ (transform[12] * 1 + x) , (transform[13] * 1 + y) ]);
}
}
}
}
function MarkerNotePlus(map, post_url)
{
var marker_width = 30;
var marker_height = 30;
var note_displayed = true;
this.location = map.getCenter();
var data = this.data = {
'lat': this.location.lat,
'lon': this.location.lon,
'marker_number': markerNumber,
'user_id': current_user_id,
'note': ''
};
this.location = map.getCenter();
var div = document.createElement('div');
div.className = 'marker';
var img = document.createElement('img');
img.src = 'img/icon_x_mark_new.png';
div.appendChild(img);
var new_marker_text_area = document.getElementById('new_marker_textarea');
var submitNote = function()
{
if (new_marker_text_area.value.trim() == ''){
alert('Please fill out your note!');
return false;
} else {
reqwest({
url: post_url,
method: 'post',
data: data,
type: 'json',
error: function(err) {
console.log('error', err);
},
success: function (resp) {
//console.log('resp', resp);
changeMarkerDisplay(resp);
}
});
active_marker = false;
note_displayed = false;
return false;
}
}
var changeMarkerDisplay = function(resp)
{
new_marker_text_area.value = '';
div.parentNode.removeChild(div);
var new_marker_note = document.getElementById('new_marker_note');
new_marker_note.className = 'hide';
var note = resp.note_data;
if (!note.username)
{
note.username = 'Anonymous';
}
addSavedNote(note.note,note.username,note.created,note.marker_number,note.latitude,note.longitude);
}
var removeMarkerNote = function()
{
div.parentNode.removeChild(div);
var editable_new_note = document.getElementById('new_marker_note');
editable_new_note.className = 'hide';
active_marker = false;
note_displayed = false;
}
var input_lat = document.createElement('input');
input_lat.value = this.location.lat.toFixed(6);
input_lat.type = 'hidden';
input_lat.name = 'marker[' + markerNumber + '][lat]';
div.appendChild(input_lat);
var input_lon = document.createElement('input');
input_lon.value = this.location.lon.toFixed(6);
input_lon.type = 'hidden';
input_lon.name = 'marker[' + markerNumber + '][lon]';
div.appendChild(input_lon);
var scan_id = document.createElement('input');
scan_id.value = scan_id;
scan_id.name = 'marker[' + markerNumber + '][scan_id]';
scan_id.type = 'hidden';
div.appendChild(scan_id);
var user_id = document.createElement('input');
user_id.value = current_user_id;
user_id.name = 'marker[' + markerNumber + '][scan_id]';
user_id.type = 'hidden';
div.appendChild(user_id);
markerNumber--;
// make it easy to drag
img.onmousedown = function(e)
{
if (active_polygon != -1 || (active_marker && !note_displayed) || draw_mode)
{
return;
}
active_marker = true;
note_displayed = true;
var ok_button = document.getElementById('new_marker_ok_button');
ok_button.onclick = submitNote;
var remove_button = document.getElementById('new_marker_delete_button');
remove_button.onclick = removeMarkerNote;
var editable_new_note = document.getElementById('new_marker_note');
editable_new_note.className = 'show';
var editable_new_note_textarea = document.getElementById('new_marker_textarea');
editable_new_note_textarea.onchange = function () {
data.note = this.value;
};
//var marker_width = 30;
var offsetY = 5;
editable_new_note.style.position = "absolute";
editable_new_note.style.left = div.offsetLeft - .5*editable_new_note.offsetWidth + .5*marker_width + 'px';
editable_new_note.style.top = div.offsetTop - editable_new_note.offsetHeight - offsetY + 'px';
var marker_start = {x: div.offsetLeft, y: div.offsetTop},
mouse_start = {x: e.clientX, y: e.clientY};
var note_start = {x: editable_new_note.offsetLeft, y: editable_new_note.offsetTop};
document.onmousemove = function(e)
{
var mouse_now = {x: e.clientX, y: e.clientY};
div.style.left = (marker_start.x + mouse_now.x - mouse_start.x) + 'px';
div.style.top = (marker_start.y + mouse_now.y - mouse_start.y) + 'px';
editable_new_note.style.left = (note_start.x + mouse_now.x - mouse_start.x) + 'px';
editable_new_note.style.top = (note_start.y + mouse_now.y - mouse_start.y) + 'px';
}
return false;
}
var marker = this;
img.onmouseup = function(e)
{
var marker_end = {x: div.offsetLeft + .5 * marker_width, y: div.offsetTop + .5 * marker_height};
marker.location = map.pointLocation(marker_end);
data.lat = marker.location.lat.toFixed(6);
data.lon = marker.location.lon.toFixed(6);
document.onmousemove = null;
return false;
}
// add it to the map
this.updatePosition = function()
{
console.log(marker_width, marker_height);
var point = map.locationPoint(marker.location);
div.style.left = point.x + - .5 * marker_width + 'px';
div.style.top = point.y - .5 * marker_height + 'px';
if (note_displayed)
{
//var marker_width = 30;
var offsetY = 5;
var editable_new_note = document.getElementById('new_marker_note');
//console.log(div.offsetLeft,editable_new_note.offsetWidth,marker_width);
editable_new_note.style.left = div.offsetLeft - .5*editable_new_note.offsetWidth + .5*marker_width + 'px';
editable_new_note.style.top = div.offsetTop - editable_new_note.offsetHeight - offsetY + 'px';
}
}
map.addCallback('panned', this.updatePosition);
map.addCallback('zoomed', this.updatePosition);
this.updatePosition();
var ok_button = document.getElementById('new_marker_ok_button');
ok_button.onclick = submitNote;
var remove_button = document.getElementById('new_marker_delete_button');
remove_button.onclick = removeMarkerNote;
var editable_new_note_textarea = document.getElementById('new_marker_textarea');
editable_new_note_textarea.onchange = function () {
data.note = this.value;
};
return [this, div];
}
for(var rd=0;rd<reddots.length;rd++){
// reduce red dots so they must be >10px from each other
var nearRed = false;
for(var r2=0;r2<rd;r2++){
var dist = Math.pow((reddots[rd][0] - reddots[r2][0]),2) + Math.pow((reddots[rd][1] - reddots[r2][1]), 2);
if(dist < 100){
nearRed = true;
break;
}
}
if(nearRed){
continue;
}
var myloc = map.pointLocation( { x: reddots[rd][0], y: reddots[rd][1] } );
mark(myloc);
}
for(var rd=0;rd<bluedots.length;rd++){
// reduce blue dots so they must be >10px from each other
var nearBlue = false;
for(var r2=0;r2<rd;r2++){
var dist = Math.pow((bluedots[rd][0] - bluedots[r2][0]),2) + Math.pow((bluedots[rd][1] - bluedots[r2][1]), 2);
if(dist < 100){
nearBlue = true;
break;
}
}
if(nearBlue){
continue;
}
var myloc = map.pointLocation( { x: bluedots[rd][0], y: bluedots[rd][1] } );
mark(myloc);
}
function mark(myloc){
var marker_width = 30;
var marker_height = 30;
changeNoteButtonStyle('marker');
var markerInfo = new MarkerNotePlus(map, post_url);
var markerSelf = markerInfo[0];
var markerDiv = markerInfo[1];
document.getElementById('marker-container').appendChild(markerDiv);
var editable_new_note = document.getElementById('new_marker_note');
editable_new_note.className = 'show';
//var marker_width = 30;
var offsetY = 5;
editable_new_note.style.position = "absolute";
editable_new_note.style.left = markerDiv.offsetLeft - .5*editable_new_note.offsetWidth + .5*marker_width + 'px';
editable_new_note.style.top = markerDiv.offsetTop - editable_new_note.offsetHeight - offsetY + 'px';
active_marker = true;
note_displayed = true;
markerSelf.location = myloc;
markerSelf.data.lat = markerSelf.location.lat.toFixed(6);
markerSelf.data.lon = markerSelf.location.lon.toFixed(6);
markerSelf.updatePosition();
}
// collect the markers and restyle them
// catch new markers and give them the same style
var markers = document.getElementsByClassName("marker");
var markerLength = 0;
setInterval( function(){
if( markers.length > markerLength ){
var oldMarkerLength = markerLength;
markerLength = markers.length;
for(var m=oldMarkerLength; m<markers.length; m++){
markers[m].children[0].src = "http://i.imgur.com/fxQyD.png";
markers[m].children[0].onmouseover = function(e){
if (active_polygon == -1 && !active_marker && !draw_mode){
//img.src = 'img/icon_x_mark_hover.png';
if(data.created){
var date = new Date(data.created*1000);
var day = date.getDate();
var month = date.getMonth();
var year = date.getFullYear();
var formatted_date = (parseInt(month) + 1) + '/' + day + '/' + year;
saved_note.innerHTML = data.note + '<br><br>' + user + ', ' + formatted_date;
}
else{
saved_note.innerHTML = data.note;
}
//var marker_width = 30;
var offsetY = 5;
saved_note.className = 'show';
saved_note.style.position = "absolute";
saved_note.style.left = div.offsetLeft - .5*saved_note.offsetWidth + .5*marker_width + 'px';
saved_note.style.top = div.offsetTop - saved_note.offsetHeight - offsetY + 'px';
}
else{
img.style.cursor = 'default';
}
};
markers[m].children[0].onmouseout = function(e){
if (active_marker) {
return;
}
//img.src = 'img/icon_x_mark.png';
img.style.cursor = 'move';
if (saved_note.className = 'show'){
saved_note.className = 'hide';
}
};
}
}
}, 250);
// have marker tool match new marker icon
document.getElementById("marker_button").style.background = 'url("http://i.imgur.com/fxQyD.png") no-repeat';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment