We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 18913
    • 654 Posts
    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
    [!phototagging_content!]

    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
    • Last Of The Romans Reply #2, 14 years ago
      beautiful!
      must test...

      thanks for sharing.
        palma non sine pulvere
        • 26931
        • 2,314 Posts
        anonymized-26931 Reply #3, 14 years ago
        hey Matt,

        that looks great, thanks for sharing! how’s the image added to the ressource? (so that you’re able to tag it)
        j
          • 18913
          • 654 Posts
          how’s the image added to the ressource? (so that you’re able to tag it)

          yeah .... working on that. I was thinking that since there’s the ability to do photo blogging with MaxiGallery and Jot that there might be a way of getting the tags attached in the same way Jot is assigning comments. But I haven’t even started to look at how that’s done.

          Still trying to work out the proof-of-concept. And I figured brighter minds than mine might find a use for that even if I can’t get done what I’m hoping for.
          Matt
            • 18913
            • 654 Posts
            BTW, in the above-posted code I intentionally simplified a "clean" function as I was getting an error using the escape code. That should get put back before anyone tries to use this outside of a sandbox...
              • 26931
              • 2,314 Posts
              anonymized-26931 Reply #6, 14 years ago
              So I suspect with some ingenuity this could be tied into a tag cloud snippet or dynamic category list.
              hi Matt, have you thought about connecting it with Ditto’s tagging capabilities?
                • 18913
                • 654 Posts
                Other than having used straightforward calls to Jot and Ditto, I haven’t really dug into either. So I’m open to any suggestions. Maybe taking a look at Ditto first makes sense. Thanks!
                Matt
                  • 18913
                  • 654 Posts
                  Something I’m wondering about : do I need a document resource for each tag (if I read one example correctly it sounds as though I do) or is there a way to specify the database of image-area tags as some sort of extended set of attributes for Ditto to consider, kind of like WebLoginPE has it’s extended table?

                  Just thinking out loud ...
                  MattC
                    • 26931
                    • 2,314 Posts
                    anonymized-26931 Reply #9, 14 years ago
                    or is there a way to specify the database of image-area tags as some sort of extended set of attributes for Ditto to consider, kind of like WebLoginPE has it’s extended table?
                    hope i understood you right ... [guess] since Ditto tags are set via TV they’re like an "extended set of attributes" for a ressource
                      • 18913
                      • 654 Posts
                      But doesn’t that assume that each photo is a document resource? MaxiGallery seems to be happy with the images and thumbnails living on their own in a gallery subfolder. So I was thinking along those lines - a pile of images for which the image-area tags would be held in a separate table. Then figure out if that table could be included in whatever Jot/Ditto/Taglinks/etc. use to work their magic.

                      That would make life a lot simpler than having to create resources for everything. But then again *I’m* probably the one who is thinking about this all wrong!

                      Matt