While thinking about ways of tagging images in MODx, I came across this site
http://blog.neillh.com.au/2010/03/29/photo-tagging-version-2/
which allows one to draw rectangles on an image and "tag" them, with the results stored in a MySQL database.
Sounded like something that ought to be in MODx, but I couldn’t find references to anything like that. So I did a very rough port of the guts of what Neill did there into MODx. My version of it is here
http://www.considine.net/recaptcha/index.php?id=37
The steps involved were :
- use the supplied SQL "Create" statement to create a table in the MODx database. I edited this to change "id" to "rec_id" so that it wouldn’t clash with unfriendly URL parsing.
- upload the contents of the archive to (in my case) assets/snippets/phototagging
- changed paths in the CSS files so that they worked in the context of MODx
- took a bare-bones template and added these lines to the HEAD section :
<link rel="stylesheet" href="assets/snippets/phototagging/css/style.css" type="text/css" media="screen" />
<link rel="stylesheet" type="text/css" href="assets/snippets/phototagging/css/imgareaselect-animated.css" />
<script type="text/javascript" src="assets/snippets/phototagging/js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="assets/snippets/phototagging/js/jquery.imgareaselect.pack.js"></script>
<script type="text/javascript" src="assets/snippets/phototagging/js/jquery.load.js"></script>
- added a snippet call such as
[!phototagging_function!]
after the BODY tag.
- created a document using this template and with this
as the content
- created the "phototagging_function" snippet with this content :
<?php
global $modx;
//Function to sanitize values received from the form. Prevents SQL injection
function clean($str) {
$str = @trim($str);
if(get_magic_quotes_gpc()) {
$str = stripslashes($str);
}
return $str; //$modx->db->escape($str);
}
if($_POST['tag']) {
//Sanitize the POST values
$title = clean($_POST['title']);
$x1 = $_POST['x1'];
$y1 = $_POST['y1'];
$w = $_POST['w'];
$h = $_POST['h'];
//Insert tag into database. I am capturing more data than needed from a previous version but this could be useful oneday.
$qry = " INSERT INTO phototags (rec_id, title, x1, y1, x2, y2, width, height) " .
" VALUES('', '".$title."', '".$x1."', '".$y1."', '".$_POST['x2']."', '".$_POST['y2']."', '".$w."', '".$h."') ";
$result=$modx->db->query($qry); //MattC
} elseif($_GET['delete']) {
//Sanitize the POST values
$rec_id = clean($_GET['rec_id']);
$qry = " DELETE FROM phototags where rec_id = $rec_id "; //MattC
$result=$modx->db->query($qry); //MattC
}
return;
?>
- created the "phototagging_content" snippet with this content :
<?php
global $x1, $y1, $x2, $y2, $w, $h;
$output = '';
$output .= '<h1><a href="http://www.neillh.com.au" target="_blank">Based on work by Neill Horsman</a></h1>';
$output .= '<div class="start-tagging">Click here to start tagging</div>';
$output .= '<div class="finish-tagging hide">Click here to cancel tagging</div>';
$output .= '<h1>1. Click and drag over the image where you want to tag</h1>';
$output .= '<div class="image">';
$output .= '<div id="title_container" class="hide">';
$output .= ' <form method="post" action="[~[*id*]~]" >';
$output .= ' <!-- Grab the X/Y/Width/Height -->';
$output .= ' <input type="hidden" name="x1" id="x1" value="'.$x1.'" />';
$output .= ' <input type="hidden" name="y1" id="y1" value="'.$y1.'" />';
$output .= ' <input type="hidden" name="x2" id="x2" value="'.$x2.'" />';
$output .= ' <input type="hidden" name="y2" id="y2" value="'.$y2.'" />';
$output .= ' <input type="hidden" name="w" id="w" value="'.$w.'" />';
$output .= ' <input type="hidden" name="h" id="h" value="'.$h.'" />';
$output .= ' <label for="title">2. Tag text</label><br />';
$output .= ' <input type="text" id="title" name="title" size="30" value="" maxlength="55" /><br />';
$output .= ' <input type="hidden" name="tag" value="true" />';
$output .= ' <input type="submit" value="Submit" class="" />';
$output .= ' </form>';
$output .= '</div>';
$output .= ' <img src="assets/snippets/phototagging/images/image.jpg" border="0" id="imageid" /><br /><br />';
$list_tags = array();
$qry = " SELECT rec_id, title, x1, y1, x2, y2, width, height FROM phototags ";
$results=$modx->db->query($qry) or die("Error retrieving record: " . mysql_error());
while ($row=$modx->db->getRow($results))
{
extract ($row);
$name = str_replace(' ', '-', $title);
$list_tags[] = array('rec_id' => $rec_id, 'title' => $title);
$output .= '<!-- Style for the tagged area -->';
$output .= '<style type="text/css">';
$output .= ' .map a.'.$name.' { border:1px solid #000; top:'.$y1.'px; left:'.$x1.'px; width:'.$width.'px; height:'.$height.'px; }';
$output .= ' .map a:hover.'.$name.' { border:3px solid #fff; }';
$output .= '</style>';
$output .= '<!-- Tags displayed as a list -->';
$output .= '<ul class="map">';
$output .= ' <li><a class="'.$name.'"><span><b>'.$title.'</b></span></a></li>';
$output .= '</ul>';
}
$output .= '</div>';
$output .= '<p>In this photo:';
foreach ($list_tags as $value)
{
$output .= "<a href='" . str_replace(' ', '-',$value['title']) . "'>" . $value['title'] . "</a> (<a href=[~[*id*]~]&delete=true&rec_id=" . $value['rec_id'] . ">Delete</a>) ";
}
$output .= '</p>';
return $output;
?>
So I suspect with some ingenuity this could be tied into a tag cloud snippet or dynamic category list.
In any case, I thought this might help someone else. And if anyone has pointers to similar/better implementations of this sort of thing - or improvements to the above to tighten things up - I’d appreciate hearing about it.
Lastly, I’d like to publiclly thank Neill for his work on this and for making it available.
TIA,
MattC