trojal.

(adventures in web programming.)

Recent Entries
Categories
Meta (2)
Test (3)
Random (1)
jQuery (1)
SVG (1)
Links
Info
Edit

SVG Interactions

-trojal @ 2010-Jan-27 01:08 UTC

SVG, as you may or may not know, stands for Scalable Vector Graphics (w3c, wikipedia). Firefox (XULrunner) and Safari/Chrome (Webkit) have native support for displaying SVG images, but Internet Explorer requires a plugin from Adobe to display them. An interesting thing about SVG is that it supports the DOM. In addition to just supporting the DOM, it also supports JavaScript (and JavaScript events). So I started working with interactive SVG to display, zoom, and scroll a view panel of various triangles.

Step 1: Basic triangles

(link)

The Interaction

Left click adds a new triangle in the appropriate location. Right click removes a triangle (as long as it is not the base triangle.

The SVG

<svg width="500" height="433.012701892" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g id="base">
<polygon points="0,433.012701892 250,0 500,433.012701892" id="a"/>
</g>
<script>
...
</script>
</svg>

The JavaScript

document.getElementById('a').setAttribute('style', 'fill: rgb(' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + '); stroke: rgb(0, 0, 0); stroke-width: 1;');
 
function addChild(e){
  var rightclick;
  if (!e) var e = window.event;
  if (e.which) rightclick = (e.which == 3);
  else if (e.button) rightclick = (e.button == 2);
  if(rightclick){
    if(this.id!='a')
      document.getElementById('base').removeChild(this);
    return false;
  }
  var posx = 0;
  var posy = 0;
  if (!e) var e = window.event;
  if (e.pageX || e.pageY) {
    posx = e.pageX;
    posy = e.pageY;
  } else if (e.clientX || e.clientY) {
    posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
    posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; }
  var v0 = new Array((this.points.getItem(2).x-this.points.getItem(1).x)/2, (this.points.getItem(2).y-this.points.getItem(1).y)/2);
  var v1 = new Array((this.points.getItem(2).x-this.points.getItem(0).x)/2, (this.points.getItem(2).y-this.points.getItem(0).y)/2);
  var v2 = new Array(posx - (this.points.getItem(0).x+this.points.getItem(1).x)/2, posy - (this.points.getItem(0).y+this.points.getItem(1).y)/2);
  dot00 = dot(v0, v0);
  dot01 = dot(v0, v1);
  dot02 = dot(v0, v2);
  dot11 = dot(v1, v1);
  dot12 = dot(v1, v2);
  invDenom = 1 / (dot00 * dot11 - dot01 * dot01)
  u = (dot11 * dot02 - dot01 * dot12) * invDenom
  v = (dot00 * dot12 - dot01 * dot02) * invDenom
  if (u<0 && v>0){
    //alert('outside');
    newPoly = document.createElementNS('http://www.w3.org/2000/svg','polygon');
    newPoly.setAttribute('id', this.id + 'c');
    newPoly.setAttribute('points', (this.points.getItem(0).x+this.points.getItem(1).x)/2 + ',' + (this.points.getItem(0).y+this.points.getItem(1).y)/2 + ' ' + this.points.getItem(1).x + ',' + this.points.getItem(1).y + ' ' + (this.points.getItem(1).x+this.points.getItem(2).x)/2 + ',' + (this.points.getItem(1).y+this.points.getItem(2).y)/2);
    newPoly.setAttribute('style', 'fill: rgb(' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + '); stroke: rgb(0, 0, 0); stroke-width: 1;');
    newPoly.onmousedown = addChild;
    document.getElementById('base').appendChild(newPoly);
  } else if (u>0 && v<0) {
    //alert('left');
    newPoly = document.createElementNS('http://www.w3.org/2000/svg','polygon');
    newPoly.setAttribute('id', this.id + 'c');
    newPoly.setAttribute('points', this.points.getItem(0).x + ',' + this.points.getItem(0).y + ' ' + (this.points.getItem(0).x+this.points.getItem(1).x)/2 + ',' + (this.points.getItem(0).y+this.points.getItem(1).y)/2 + ' ' + (this.points.getItem(0).x+this.points.getItem(2).x)/2 + ',' + (this.points.getItem(0).y+this.points.getItem(2).y)/2);
    newPoly.setAttribute('style', 'fill: rgb(' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + '); stroke: rgb(0, 0, 0); stroke-width: 1;');
    newPoly.onmousedown = addChild;
    document.getElementById('base').appendChild(newPoly);
  } else if (u>0 && v>0) {
    if(u+v>1) {
      //alert('right');
      newPoly = document.createElementNS('http://www.w3.org/2000/svg','polygon');
      newPoly.setAttribute('id', this.id + 'c');
      newPoly.setAttribute('points', (this.points.getItem(0).x+this.points.getItem(2).x)/2 + ',' + (this.points.getItem(0).y+this.points.getItem(2).y)/2 + ' ' + (this.points.getItem(1).x+this.points.getItem(2).x)/2 + ',' + (this.points.getItem(1).y+this.points.getItem(2).y)/2 + ' ' + this.points.getItem(2).x + ',' + this.points.getItem(2).y);
      newPoly.setAttribute('style', 'fill: rgb(' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + '); stroke: rgb(0, 0, 0); stroke-width: 1;');
      newPoly.onmousedown = addChild;
      document.getElementById('base').appendChild(newPoly);
    } else {
      //alert('center');
      newPoly = document.createElementNS('http://www.w3.org/2000/svg','polygon');
      newPoly.setAttribute('id', this.id + 'c');
      newPoly.setAttribute('points', (this.points.getItem(0).x+this.points.getItem(1).x)/2 + ',' + (this.points.getItem(0).y+this.points.getItem(1).y)/2 + ' ' + (this.points.getItem(0).x+this.points.getItem(2).x)/2 + ',' + (this.points.getItem(0).y+this.points.getItem(2).y)/2 + ' ' + (this.points.getItem(1).x+this.points.getItem(2).x)/2 + ',' + (this.points.getItem(1).y+this.points.getItem(2).y)/2);
      newPoly.setAttribute('style', 'fill: rgb(' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + ', ' + Math.round(255*Math.random()) + '); stroke: rgb(0, 0, 0); stroke-width: 1;');
      newPoly.onmousedown = addChild;
      document.getElementById('base').appendChild(newPoly);
    }
  } else {
  }
}
 
 
function dot(vec1, vec2){
  return vec1[0]*vec2[0] + vec1[1]*vec2[1];
}
 
window.oncontextmenu = function () { return false; }
document.getElementById('a').onmousedown = addChild;

Next up: Step 2: Zoom and Triangle child removal

jQuery magicText

-trojal @ 2009-Oct-26 01:07 UTC
So I was taking to learning jQuery, because it was recommended by someone (Nate) and it seemed like a reasonable enough Javascript library for the kinds of things I do with JS.
function spanWords(element){
  var a = $(element).clone().empty();
  $($(element).html().split(" ")).each(function() {
    a.append('<span class="magicText">' + this + '</span> ');
  });
  $(element).replaceWith(a);
}
 
$(document).ready(function() {
  $('.magicText').live('click', function(){
    var a = $($('.magicText').get(Math.floor(Math.random() * $('.magicText').size()))).text();
    if($(this).text().charAt(0) != $(this).text().charAt(0).toLowerCase())
      a = a.charAt(0).toUpperCase() + a.slice(1);
    else
      a = a.toLowerCase();
    if(/\.$/.test(a))
      a = a.slice(0,a.length-1);
    if(/\.$/.test($(this).text()))
      a += $(this).text().charAt($(this).text().length-1);
 
    $(this).text(a);
  });
  $('.text').each(function() {
    spanWords(this);
  });
});
This first adventure in jQuery was just a simple script to automatically break any element containing a text node into spans based on word boundaries created by spaces, and adding an onclick event to those spans that would change their text to that of another of the spans.
The important part was to have minimal interference into the structure of the page and still have a nice effect:
<h2 class="text">Lorem Ipsum</h2>
<div class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
So I just add the class "text" to the element containing, well, a text node with words in it and the javascript takes care of the rest. Also, as an added bonus, I added the script to the text here.

Two and Two

-trojal @ 2009-Feb-12 18:12 UTC
Two and two equals:
2 + 2 = 4		2 & 2 = 2		2 && 2 = 1		
2 + '2' = 4		2 & '2' = 2		2 && '2' = 1		
2 + 'two' = 2		2 & 'two' = 0		2 && 'two' = 1		
'2' + 2 = 4		'2' & 2 = 2		'2' && 2 = 1		
'2' + '2' = 4		'2' & '2' = 2		'2' && '2' = 1		
'2' + 'two' = 2		'2' & 'two' = 0		'2' && 'two' = 1		
'two' + 2 = 2		'two' & 2 = 0		'two' && 2 = 1		
'two' + '2' = 2		'two' & '2' = 0		'two' && '2' = 1		
'two' + 'two' = 0	'two' & 'two' = two	'two' && 'two' = 1	
I overheard someone say "1 and 1 makes 2" in terms of who knows what, and... I decided to find the different ways to interpret it. This is just PHP code, so it treats (int) + (string) by parsing the string as an integer (leading numeric characters = number, else it takes the value of 0).
<?php
function add($arg1, $arg2){
  return $arg1+$arg2;
}
 
function bit($arg1, $arg2){
  return $arg1 & $arg2;
}
 
function compare($arg1, $arg2){
  return ($arg1 && $arg2);
}
 
$two = array("2"=>2, "'2'"=>'2', "'two'"=>'two');
$add = array("+"=>'add', "&"=>'bit', "&&"=>'compare');
 
foreach($two as $key1=>$arg1){
  foreach($two as $key2=>$arg2){
    foreach($add as $funckey=>$func){
      echo $key1 . " " . $funckey . " " . $key2 . " = " . $func($arg1, $arg2) .
        (($arg1=="two" && $arg2=="two")?"":"\t") . "\t";
    }
    echo "\n";
  }
}
?>