Skip to content

Instantly share code, notes, and snippets.

@bkardell
Created December 16, 2011 21:10
Show Gist options
  • Save bkardell/1487991 to your computer and use it in GitHub Desktop.
Save bkardell/1487991 to your computer and use it in GitHub Desktop.
dumb tag cloud example
<html>
<head>
<link rel="stylesheet"
type="text/css"
href="http://69.54.28.122/describe.css" />
</head>
<body>
<h1>Goat Tag Cloud Hitch Level 1 (<script type="text/javascript">document.write(window.location.href.replace(/.html/,'.js').replace('http://69.54.28.122:8081/describe?u=',''));</script>)</h1>
<h2>Goat Tag Cloud Attributes</h2>
<p>Custom hitch which allows you to use the <a href="http://www.goat1000.com/tagcanvas.php">goat 1000 HTML5 canvas tag cloud via vendor attributes as a standard via -hitch-requires.
</p>
<h2></h2>
<ol>
<li><a href="#basic">Basic Usage in HTML</a></li>
<li><a href="#pluginAttributes">Optional Hitch Attributes</a>
<ol>
<li>data-goat-weightMode</li>
<li>data-goat-weightMultiplier</li>
<li>data-goat-wheelZoom</li>
<li>data-goat-lock</li>
<li>data-goat-zoomMin</li>
<li>data-goat-zoomMax</li>
</ol>
</li>
<li><a href="#linkAttributes">Optional Link Attributes</a>
<ol>
<li>data-goat-weight</li>
</ol>
</li>
</ol>
<h3 class="sectionnumber"><a name="basic">1. Basic Usage in HTML</a></h3>
<p> In order to use, require the plugin url on any block element and fill that element with
anchor tags. By default you do not need to supply any additional configuration. The size of
the tag cloud and the text color will be determined from your CSS.
See <a href="#pluginAttributes">Optional Plugin Attributes</a> for more details on optional
arguments and what their defaults are if not explicitly specified.
</p>
<div class="example">
<p>Examples: </p>
<p>
The following HTML will create a tag cloud out of the links inside..
</p>
<pre>&lt;div x-hitch-requires="<script type="text/javascript">document.write(window.location.href.replace(/.html/,'.js').replace('http://69.54.28.122:8081/describe?u=',''));</script>"
-goat-tagCloud &gt;
&lt;a href="one.html"&gt;One&lt;/a&gt;
&lt;a href="two.html"&gt;Two&lt;/a&gt;
&lt;a href="three.html"&gt;Three&lt;/a&gt;
&lt;div&gt;</pre>
</div>
<h3 class="sectionnumber"><a name="pluginAttributes">2. Optional Plugin Attributes</a></h3>
<p>The following attributes are optional and may be placed on the same element as -goat-tagCloud.
Their explanation and defaults are described in the
table below.
</p>
<table>
<thead>
<tr>
<th style="width:200px">Option</th>
<th style="width:120px">Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>data-goat-weightMode</td>
<td>size</td>
<td>Method to use for displaying tag weights. Should be one of size, colour or both.</td>
</tr>
<tr>
<td>data-goat-weightMultiplier</td>
<td>1.0</td>
<td>Multiplier for adjusting the size of tags when using a weight mode of size or both.</td>
</tr>
<tr>
<td>data-goat-wheelZoom</td>
<td>true (present)</td>
<td>Enables zooming the cloud in and out using the mouse wheel or scroll gesture. Boolean attribute, presence is true - don't write "false".</td>
</tr>
<tr>
<td>data-goat-lock</td>
<td>None</td>
<td>A value of "x" limits rotation of the cloud to the (horizontal) x-axis, and a value of "y" limits rotation to the (vertical) y-axis. (These are strings, so the quotes are required)</td>
</tr>
<tr>
<td>data-goat-zoomMin</td>
<td>Default</td>
<td>Minimum zoom value - only applies if -goat-wheelZoom is present.</td>
</tr>
<tr>
<td>data-goat-zoomMax</td>
<td>size</td>
<td>Maximum zoom value - only applies if -goat-wheelZoom is present.</td>
</tr>
</tbody>
</table>
<div class="example">
<p>Examples: </p>
<p>
The following HTML will make the colors as well as the size of links weighted:
</p>
<pre>&lt;div x-hitch-requires="<script type="text/javascript">document.write(window.location.href.replace(/.html/,'.js').replace('http://69.54.28.122:8081/describe?u=',''));</script>"
-goat-tagCloud
-goat-weightMode="both" &gt;
&lt;a href="one.html"&gt;One&lt;/a&gt;
&lt;a href="two.html"&gt;Two&lt;/a&gt;
&lt;a href="three.html"&gt;Three&lt;/a&gt;
&lt;/div&gt;</pre>
</div>
<h3 class="sectionnumber"><a name="linkAttributes">3. Optional Link Attributes</a></h3>
<p>The following attributes are optional and may be placed on the anchor tags inside the element with the data-goat-tagCloud attribute.</p>
<table>
<thead>
<tr>
<th style="width:200px">Option</th>
<th style="width:120px">Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>data-goat-weight</td>
<td>15</td>
<td>A numeric weight value (generally 0-100 with default multiplier)</td>
</tr>
</tbody>
</table>
<div class="example">
<p>Examples: </p>
<p>Given the following html, the rule above would make background of the third div yellow:
<pre>&lt;div x-hitch-requires="<script type="text/javascript">document.write(window.location.href.replace(/.html/,'.js').replace('http://69.54.28.122:8081/describe?u=',''));</script>"
data-goat-tagCloud &gt;
&lt;a href="one.html" data-goat-weight="20" &gt;One&lt;/a&gt;
&lt;a href="two.html" data-goat-weight="40" &gt;Two&lt;/a&gt;
&lt;a href="three.html" data-goat-weight="14" &gt;Three&lt;/a&gt;
&lt;/div&gt;</pre>
</div>
</body>
</html>
(function(){
var i,
j,
abs = Math.abs,
sin = Math.sin,
cos = Math.cos,
hexlookup3 = {},
hexlookup2 = {},
hexlookup1 = {
0:"0,", 1:"17,", 2:"34,", 3:"51,", 4:"68,", 5:"85,",
6:"102,", 7:"119,", 8:"136,", 9:"153,", a:"170,", A:"170,",
b:"187,", B:"187,", c:"204,", C:"204,", d:"221,", D:"221,",
e:"238,", E:"238,", f:"255,", F:"255,"
},
Oproto,
Tproto,
TCproto,
doc = document;
for(i = 0; i < 256; ++i) {
j = i.toString(16);
if(i < 16)
j = '0' + j;
hexlookup2[j] = hexlookup2[j.toUpperCase()] = i.toString() + ',';
};
var Defined = function(d) {
return typeof(d) != 'undefined';
};
var PointsOnSphere = function(n) {
var i, y, r, phi, pts = [], inc = Math.PI * (3-Math.sqrt(5)), off = 2/n;
for(i = 0; i < n; ++i) {
y = i * off - 1 + (off / 2);
r = Math.sqrt(1 - y*y);
phi = i * inc;
pts.push([cos(phi)*r, y, sin(phi)*r]);
}
return pts;
};
var Cylinder = function(n,o,i,j,k,l) {
var phi, pts = [], inc = Math.PI * (3-Math.sqrt(5)), off = 2/n;
for(i = 0; i < n; ++i) {
j = i * off - 1 + (off / 2);
phi = i * inc;
k = cos(phi);
l = sin(phi);
pts.push(o ? [j, k, l] : [k, j, l]);
}
return pts;
};
var PointsOnCylinderV = function(n) { return Cylinder(n) };
var PointsOnCylinderH = function(n) { return Cylinder(n,1) };
var SetAlpha = function(c,a) {
var d = c, p1, p2, ae = (a*1).toPrecision(3) + ')';
if(c[0] === '#') {
if(!hexlookup3[c])
if(c.length === 4)
hexlookup3[c] = 'rgba(' + hexlookup1[c[1]] + hexlookup1[c[2]] + hexlookup1[c[3]];
else
hexlookup3[c] = 'rgba(' + hexlookup2[c.substr(1,2)] + hexlookup2[c.substr(3,2)] + hexlookup2[c.substr(5,2)];
d = hexlookup3[c] + ae;
} else if(c.substr(0,4) === 'rgb(' || c.substr(0,4) === 'hsl(') {
d = (c.replace('(','a(').replace(')', ',' + ae));
} else if(c.substr(0,5) === 'rgba(' || c.substr(0,5) === 'hsla(') {
p1 = c.lastIndexOf(',') + 1, p2 = c.indexOf(')');
a *= parseFloat(c.substring(p1,p2));
d = c.substr(0,p1) + a.toPrecision(3) + ')';
}
return d;
};
var NewCanvas = function(w,h) {
// if using excanvas, give up now
if(window.G_vmlCanvasManager)
return null;
var c = doc.createElement('canvas');
c.width = w;
c.height = h;
return c;
};
// I think all browsers pass this test now...
var ShadowAlphaBroken = function() {
var cv = NewCanvas(3,3), c, i;
if(!cv)
return false;
c = cv.getContext('2d');
c.strokeStyle = '#000';
c.shadowColor = '#fff';
c.shadowBlur = 3;
c.globalAlpha = 0;
c.strokeRect(2,2,2,2);
c.globalAlpha = 1;
i = c.getImageData(2,2,1,1);
cv = null;
return (i.data[0] > 0);
};
var FindGradientColour = function(t,p) {
var l = 1024, g = t.weightGradient, cv, c, i, gd, d;
if(t.gCanvas) {
c = t.gCanvas.getContext('2d');
} else {
t.gCanvas = cv = NewCanvas(l,1);
if(!cv)
return null;
c = cv.getContext('2d');
gd = c.createLinearGradient(0,0,l,0);
for(i in g)
gd.addColorStop(1-i, g[i]);
c.fillStyle = gd;
c.fillRect(0,0,l,1);
}
d = c.getImageData(~~((l-1)*p),0,1,1).data;
return 'rgba(' + d[0] + ',' + d[1] + ',' + d[2] + ',' + (d[3]/255) + ')';
};
var TextSet = function(c,f,l,s,sc,sb,so) {
var xo = (sb || 0) + (so && so[0] < 0 ? abs(so[0]) : 0),
yo = (sb || 0) + (so && so[1] < 0 ? abs(so[1]) : 0);
c.font = f;
c.textBaseline = 'top';
c.fillStyle = l;
sc && (c.shadowColor = sc);
sb && (c.shadowBlur = sb);
so && (c.shadowOffsetX = so[0], c.shadowOffsetY = so[1]);
c.fillText(s, xo, yo);
};
var TextToCanvas = function(s,f,ht,w,h,l,sc,sb,so) {
var cw = w + abs(so[0]) + sb + sb, ch = h + abs(so[1]) + sb + sb, cv, c;
cv = NewCanvas(cw,ch);
if(!cv)
return null;
c = cv.getContext('2d');
TextSet(c,f,l,s,sc,sb,so);
return cv;
};
var AddShadowToImage = function(i,sc,sb,so) {
var cw = i.width + abs(so[0]) + sb + sb, ch = i.height + abs(so[1]) + sb + sb, cv, c,
xo = (sb || 0) + (so && so[0] < 0 ? abs(so[0]) : 0),
yo = (sb || 0) + (so && so[1] < 0 ? abs(so[1]) : 0);
cv = NewCanvas(cw,ch);
if(!cv)
return null;
c = cv.getContext('2d');
sc && (c.shadowColor = sc);
sb && (c.shadowBlur = sb);
so && (c.shadowOffsetX = so[0], c.shadowOffsetY = so[1]);
c.drawImage(i, xo, yo);
return cv;
};
var FindTextBoundingBox = function(s,f,ht) {
var w = parseInt(s.length * ht), h = parseInt(ht * 2), cv = NewCanvas(w,h), c, idata, w1, h1, x, y, i, ex;
if(!cv)
return null;
c = cv.getContext('2d');
c.fillStyle = '#000';
c.fillRect(0,0,w,h);
TextSet(c,ht + 'px ' + f,'#fff',s)
idata = c.getImageData(0,0,w,h);
w1 = idata.width; h1 = idata.height;
ex = {
min: { x: w1, y: h1 },
max: { x: -1, y: -1 }
};
for(y = 0; y < h1; ++y) {
for(x = 0; x < w1; ++x) {
i = (y * w1 + x) * 4;
if(idata.data[i+1] > 0) {
if(x < ex.min.x) ex.min.x = x;
if(x > ex.max.x) ex.max.x = x;
if(y < ex.min.y) ex.min.y = y;
if(y > ex.max.y) ex.max.y = y;
}
}
}
// device pixels might not be css pixels
if(w1 != w) {
ex.min.x *= (w / w1);
ex.max.x *= (w / w1);
}
if(h1 != h) {
ex.min.y *= (w / h1);
ex.max.y *= (w / h1);
}
cv = null;
return ex;
};
var FixFont = function(f) {
return "'" + f.replace(/(\'|\")/g,'').replace(/\s*,\s*/g, "', '") + "'";
};
var AddHandler = function(h,f,e) {
e = e || doc;
if(e.addEventListener)
e.addEventListener(h,f,false);
else
e.attachEvent('on' + h, f);
};
var AddImage = function(i,t,tl) {
if(i.complete) {
t.w = i.width;
t.h = i.height;
tl.push(t);
} else {
AddHandler('load',function() {
t.w = this.width;
t.h = this.height;
tl.push(t);
},i);
}
};
var FindWeight = function(t,a) {
var w = 1, p;
if(t.weightFrom) {
w = 1 * (a.getAttribute(t.weightFrom) || t.textHeight);
} else if(doc.defaultView && doc.defaultView.getComputedStyle) {
p = doc.defaultView.getComputedStyle(a,null).getPropertyValue('font-size');
w = p.replace('px','') * 1;
} else {
t.weight = false;
}
return w;
};
var MouseMove = function(e) {
var i, tc, dd = doc.documentElement, p;
for(i in TagCanvas.tc) {
tc = TagCanvas.tc[i];
p = AbsPos(i);
if(e.pageX) {
tc.mx = e.pageX - p.x;
tc.my = e.pageY - p.y;
} else {
tc.mx = e.clientX + (dd.scrollLeft || doc.body.scrollLeft) - p.x;
tc.my = e.clientY + (dd.scrollTop || doc.body.scrollTop) - p.y;
}
}
};
var MouseClick = function(e) {
var t = TagCanvas, cb = doc.addEventListener ? 0 : 1,
tg = e.target && Defined(e.target.id) ? e.target.id : e.srcElement.parentNode.id;
if(tg && e.button == cb && t.tc[tg]) {
MouseMove(e);
t.tc[tg].Clicked(e);
}
};
var MouseWheel = function(e) {
var t = TagCanvas,
tg = e.target && Defined(e.target.id) ? e.target.id : e.srcElement.parentNode.id;
if(tg && t.tc[tg]) {
e.cancelBubble = true;
e.returnValue = false;
e.preventDefault && e.preventDefault();
t.tc[tg].Wheel((e.wheelDelta || e.detail) > 0);
}
};
var DrawCanvas = function() {
var t = TagCanvas.tc, i;
for(i in t)
t[i].Draw();
};
var AbsPos = function(id) {
var e, p, pn;
e = doc.getElementById(id);
p = {x:e.offsetLeft,y:e.offsetTop};
while(e.offsetParent) {
pn = e.offsetParent;
p.x += pn.offsetLeft;
p.y += pn.offsetTop;
e = pn;
}
return p;
};
var RotX = function(p1,t) {
var s = sin(t), c = cos(t);
return {x:p1.x, y:(p1.y * c) + (p1.z * s), z:(p1.y * -s) + (p1.z * c)};
};
var RotY = function(p1,t) {
var s = sin(t), c = cos(t);
return {x:(p1.x * c) + (p1.z * -s), y:p1.y, z:(p1.x * s) + (p1.z * c)};
};
var Project = function(tc,p1,w,h,fov,asp) {
var yn, xn, zn, m = tc.z1 / (tc.z1 + tc.z2 + p1.z);
yn = p1.y * m;
xn = p1.x * m;
zn = tc.z2 + p1.z;
return {x:xn, y:yn, z:zn};
};
var Outline = function(tc) {
this.ts = new Date().valueOf();
this.tc = tc;
this.x = this.y = this.w = this.h = this.sc = 1;
this.z = 0;
};
Oproto = Outline.prototype;
Oproto.Update = function(x,y,w,h,sc,p) {
var o = this.tc.outlineOffset;
this.x = sc * (x - o);
this.y = sc * (y - o);
this.w = sc * (w + o * 2);
this.h = sc * (h + o * 2);
this.sc = sc; // used to determine frontmost
this.z = p.z;
};
Oproto.Draw = function(c) {
var diff = new Date().valueOf() - this.ts, t = this.tc;
c.setTransform(1,0,0,1,0,0);
c.strokeStyle = t.outlineColour;
c.lineWidth = t.outlineThickness;
c.shadowBlur = c.shadowOffsetX = c.shadowOffsetY = 0;
if(t.pulsateTo < 1)
c.globalAlpha = t.pulsateTo + ((1 - t.pulsateTo) *
(0.5 + (cos(2 * Math.PI * diff / (1000 * t.pulsateTime)) / 2)));
else
c.globalAlpha = 1;
c.strokeRect(this.x, this.y, this.w, this.h);
};
Oproto.Active = function(c,x,y) {
return (x >= this.x && y >= this.y &&
x <= this.x + this.w && y <= this.y + this.h);
};
/**
* @constructor
*/
function Tag(tc,name,a,v,w,h) {
var c = tc.ctxt, i;
this.tc = tc;
this.image = name.src ? name : null;
this.name = name.src ? '' : name;
this.a = a;
this.p3d = { x: v[0] * tc.radius * 1.1, y: v[1] * tc.radius * 1.1, z: v[2] * tc.radius * 1.1};
this.x = this.y = 0;
this.w = w;
this.h = h;
this.colour = tc.textColour;
this.weight = this.sc = this.alpha = 1;
this.weighted = !tc.weight;
this.outline = new Outline(tc);
if(this.image) {
if(tc.txtOpt && tc.shadow) {
i = AddShadowToImage(this.image,tc.shadow,tc.shadowBlur,tc.shadowOffset);
if(i) {
this.image = i;
this.w = i.width;
this.h = i.height;
}
}
} else {
this.textHeight = tc.textHeight;
this.extents = FindTextBoundingBox(this.name, tc.textFont, this.textHeight);
this.Measure(c,tc);
}
this.SetShadowColour = tc.shadowAlpha ? this.SetShadowColourAlpha : this.SetShadowColourFixed;
this.SetDraw(tc);
}
Tproto = Tag.prototype;
Tproto.SetDraw = function(t) {
this.Draw = this.image ? (t.ie > 7 ? this.DrawImageIE : this.DrawImage) : this.DrawText;
};
Tproto.Measure = function(c,t) {
this.h = this.extents ? this.extents.max.y + this.extents.min.y : this.textHeight;
c.font = this.font = this.textHeight + 'px ' + t.textFont;
this.w1 = c.measureText(this.name).width;
if(t.txtOpt) {
var s = t.txtScale, th = s * this.textHeight, f = th + 'px ' + t.textFont,
soff = [s*t.shadowOffset[0],s*t.shadowOffset[1]], cw;
c.font = f;
cw = c.measureText(this.name).width;
this.image = TextToCanvas(this.name, f, th, cw, s * this.h, this.colour,
t.shadow, s * t.shadowBlur, soff);
if(this.image) {
this.w = this.image.width / s;
this.h = this.image.height / s;
}
this.SetDraw(t);
t.txtOpt = this.image;
}
};
Tproto.SetWeight = function(w) {
this.weight = w;
this.Weight(this.tc.ctxt, this.tc);
this.Measure(this.tc.ctxt, this.tc);
};
Tproto.Weight = function(c,t) {
var w = this.weight, m = t.weightMode;
this.weighted = true;
if(m == 'colour' || m == 'both')
this.colour = FindGradientColour(t, (w - t.min_weight) / (t.max_weight-t.min_weight));
if(m == 'size' || m == 'both')
this.textHeight = w * t.weightSize;
this.extents = FindTextBoundingBox(this.name, t.textFont, this.textHeight);
};
Tproto.SetShadowColourFixed = function(c,s,a) {
c.shadowColor = s;
};
Tproto.SetShadowColourAlpha = function(c,s,a) {
c.shadowColor = SetAlpha(s, a);
};
Tproto.DrawText = function(c,xoff,yoff) {
var t = this.tc, x = this.x, y = this.y, w, h, s = this.sc, o = this.outline;
c.globalAlpha = this.alpha;
c.setTransform(s,0,0,s,0,0);
c.fillStyle = this.colour;
t.shadow && this.SetShadowColour(c,t.shadow,this.alpha);
c.font = this.font;
w = this.w1 * s;
h = this.h * s;
x += 1 + (xoff / s) - (w / 2);
y += 1 + (yoff / s) - (h / 2);
c.fillText(this.name, x, y);
o.Update(x, y, this.w1, this.h, s, this.p3d);
return o.Active(c, t.mx, t.my) ? o : null;
};
Tproto.DrawImage = function(c,xoff,yoff) {
var t = this.tc, x = this.x, y = this.y, s = this.sc, o = this.outline,
i = this.image, w = this.w, h = this.h;
c.globalAlpha = this.alpha;
c.setTransform(s,0,0,s,0,0);
c.fillStyle = this.colour;
t.shadow && this.SetShadowColour(c,t.shadow,this.alpha);
x += (xoff / s) - (w / 2);
y += (yoff / s) - (h / 2);
c.drawImage(i, x, y, w, h);
o.Update(x, y, w, h, s, this.p3d);
return o.Active(c, t.mx, t.my) ? o : null;
};
Tproto.DrawImageIE = function(c,xoff,yoff) {
var t = this.tc, i = this.image, s = this.sc, o = this.outline,
w = i.width = this.w*s, h = i.height = this.h * s,
x = (this.x*s) + xoff - (w/2), y = (this.y*s) + yoff - (h/2);
c.globalAlpha = this.alpha;
c.drawImage(i, x, y);
o.Update(x, y, w, h, 1, this.p3d);
return o.Active(c, t.mx, t.my) ? o : null;
};
Tproto.Calc = function(yaw,pitch) {
var pp = RotY(this.p3d,yaw), t = this.tc, mb = t.minBrightness, r = t.radius;
this.p3d = RotX(pp,pitch);
pp = Project(t, this.p3d, this.w, this.h, Math.PI / 4, 20);
this.x = pp.x;
this.y = pp.y;
this.sc = (t.z1 + t.z2 - pp.z) / t.z2;
this.alpha = Math.max(mb,Math.min(1,mb + 1 - ((pp.z - t.z2 + r) / (2 * r))));
};
Tproto.Clicked = function(e) {
var a = this.a, t = a.target, h = a.href, evt;
if(t != '' && t != '_self') {
if(self.frames[t])
self.frames[t] = h;
else if(top.frames[t])
top.frames[t] = h;
else
window.open(h, t);
return;
}
if(a.fireEvent) {
if(!a.fireEvent('onclick'))
return;
} else {
evt = doc.createEvent('MouseEvents');
evt.initMouseEvent('click', 1, 1, window, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
if(!a.dispatchEvent(evt))
return;
}
doc.location = h;
};
/**
* @constructor
*/
function TagCanvas(cid,lctr,opt) {
var i, ctr, tl, vl, p, im, ii, tag, c = doc.getElementById(cid),
cp = ['id','class','innerHTML'], w, weights = [],
pfuncs = {
sphere:PointsOnSphere,
vcylinder:PointsOnCylinderV,
hcylinder:PointsOnCylinderH
};
if(!c) throw 0;
if(Defined(window.G_vmlCanvasManager)) {
c = window.G_vmlCanvasManager.initElement(c);
this.ie = parseFloat(navigator.appVersion.split('MSIE')[1]);
}
if(c && (!c.getContext || !c.getContext('2d').fillText)) {
p = doc.createElement('DIV');
for(i = 0; i < cp.length; ++i)
p[cp[i]] = c[cp[i]];
c.parentNode.insertBefore(p,c);
c.parentNode.removeChild(c);
throw 0;
}
for(i in TagCanvas.options)
this[i] = opt && Defined(opt[i]) ? opt[i] :
(Defined(TagCanvas[i]) ? TagCanvas[i] : TagCanvas.options[i]);
this.canvas = c;
this.ctxt = c.getContext('2d');
this.z1 = (19800 / (Math.exp(this.depth) * (1-1/Math.E))) +
20000 - 19800 / (1-(1/Math.E));
this.z2 = this.z1 * (1/this.zoom);
this.radius = (c.height > c.width ? c.width : c.height)
* 0.33 * (this.z2 + this.z1) / (this.z1);
this.max_weight = 0;
this.min_weight = 200;
this.textFont = FixFont(this.textFont);
this.ctxt.textBaseline = 'top';
if(this.shadowBlur || this.shadowOffset[0] || this.shadowOffset[1]) {
// let the browser translate "red" into "#ff0000"
this.ctxt.shadowColor = this.shadow;
this.shadow = this.ctxt.shadowColor;
this.shadowAlpha = ShadowAlphaBroken();
} else {
delete this.shadow;
}
try {
ctr = doc.getElementById(lctr || cid);
tl = ctr.getElementsByTagName('a');
this.taglist = [];
if(tl.length) {
this.shape = pfuncs[this.shape] || pfuncs.sphere;
vl = this.shape(tl.length);
for(i = 0; i < tl.length; ++i) {
im = tl[i].getElementsByTagName('img');
if(im.length) {
ii = new Image;
ii.src = im[0].src;
tag = new Tag(this, ii, tl[i], vl[i], 1, 1);
AddImage(ii,tag,this.taglist);
} else {
this.taglist.push(new Tag(this, tl[i].innerText || tl[i].textContent, tl[i],
vl[i], 2, this.textHeight + 2));
}
if(this.weight) {
w = FindWeight(this,tl[i]);
if(w > this.max_weight) this.max_weight = w;
if(w < this.min_weight) this.min_weight = w;
weights.push(w);
}
}
if(this.weight = (this.max_weight > this.min_weight)) {
for(i = 0; i < this.taglist.length; ++i) {
this.taglist[i].SetWeight(weights[i]);
}
}
}
if(lctr && this.hideTags)
ctr.style.display = 'none';
} catch(ex) {
ex;
}
this.yaw = this.initial ? this.initial[0] * this.maxSpeed : 0;
this.pitch = this.initial ? this.initial[1] * this.maxSpeed : 0;
AddHandler('mousemove', MouseMove, c);
AddHandler('mouseout', MouseMove, c);
AddHandler('mouseup', MouseClick, c);
if(this.wheelZoom) {
AddHandler('mousewheel', MouseWheel, c);
AddHandler('DOMMouseScroll', MouseWheel, c);
}
TagCanvas.started || (TagCanvas.started = setInterval(DrawCanvas, this.interval));
}
TCproto = TagCanvas.prototype;
TCproto.Draw = function() {
var cv = this.canvas, cw = cv.width, ch = cv.height, max_sc = 0, yaw = this.yaw, pitch = this.pitch,
x1 = cw / 2, y1 = ch / 2, c = this.ctxt, active, a, i, tl = this.taglist, l = tl.length;
c.setTransform(1,0,0,1,0,0);
this.active = null;
for(i = 0; i < l; ++i)
tl[i].Calc(yaw, pitch);
tl = tl.sort(function(a,b) {return a.sc-b.sc});
if(!this.txtOpt && this.shadow) {
c.shadowBlur = this.shadowBlur;
c.shadowOffsetX = this.shadowOffset[0];
c.shadowOffsetY = this.shadowOffset[1];
}
c.clearRect(0,0,cw,ch);
for(i = 0; i < l; ++i) {
a = tl[i].Draw(c, x1, y1);
if(a && a.sc > max_sc && (!this.frontSelect || a.z <= 0)) {
active = a;
active.index = i;
max_sc = a.sc;
}
}
if(this.freezeActive && active)
this.yaw = this.pitch = 0;
else
this.Animate(cw, ch);
active && (this.active = active).Draw(c);
};
TCproto.Animate = function(w,h) {
var tc = this, x = tc.mx, y = tc.my, l = tc.lock, s, ay, ap, r;
if(x >= 0 && y >= 0 && x < w && y < h)
{
s = tc.maxSpeed, r = tc.reverse ? -1 : 1;
if(l != 'x')
this.yaw = r * ((s * 2 * x / w) - s);
if(l != 'y')
this.pitch = r * -((s * 2 * y / h) - s);
this.initial = null;
}
else if(!tc.initial)
{
s = tc.minSpeed, ay = abs(tc.yaw), ap = abs(tc.pitch);
if(l != 'x' && ay > s)
this.yaw = ay > tc.z0 ? tc.yaw * tc.decel : 0;
if(l != 'y' && ap > s)
this.pitch = ap > tc.z0 ? tc.pitch * tc.decel : 0;
}
};
TCproto.Zoom = function(r) {
this.z2 = this.z1 * (1/r);
};
TCproto.Clicked = function(e) {
var t = this.taglist, a = this.active;
try {
if(a && t[a.index])
t[a.index].Clicked(e);
} catch(ex) {
}
};
TCproto.Wheel = function(i) {
var z = this.zoom + this.zoomStep * (i ? 1 : -1);
this.zoom = Math.min(this.zoomMax,Math.max(this.zoomMin,z));
this.Zoom(this.zoom);
};
TagCanvas.Start = function(id,l,o) {
TagCanvas.tc[id] = new TagCanvas(id,l,o);
};
TagCanvas.tc = {};
TagCanvas.options = {
z1: 20000,
z2: 20000,
z0: 0.0002,
freezeActive: false,
pulsateTo: 0.15,
pulsateTime: 3,
reverse: false,
depth: 0.5,
maxSpeed: 0.05,
minSpeed: 0,
decel: 0.95,
interval: 20,
minBrightness: 0.1,
outlineColour: '#ffff99',
outlineThickness: 2,
outlineOffset: 5,
textColour: '#ff99ff',
textHeight: 15,
textFont: 'Helvetica, Arial, sans-serif',
shadow: '#000',
shadowBlur: 0,
shadowOffset: [0,0],
initial: null,
hideTags: true,
zoom: 1,
weight: false,
weightMode: 'size',
weightFrom: null,
weightSize: 1,
weightGradient: {0:'#f00', 0.33:'#ff0', 0.66:'#0f0', 1:'#00f'},
txtOpt: true,
txtScale: 2,
frontSelect: false,
wheelZoom: true,
zoomMin: 0.3,
zoomMax: 3,
zoomStep: 0.05,
shape: 'sphere',
lock: null
};
for(i in TagCanvas.options){
TagCanvas[i] = TagCanvas.options[i];
window.TagCanvas = TagCanvas;
};
var computedStyle = function(element, property){
var s = false;
if(element.currentStyle){
var p = property.split('-');
var str = new String('');
for(i in p){
str += (i > 0)?(p[i].substr(0, 1).toUpperCase() + p[i].substr(1)):p[i];
}
s = element.currentStyle[str];
}else if(window.getComputedStyle){
s = window.getComputedStyle(element, null).getPropertyValue(property);
}
return s.replace('px','');
};
var colorToHex = function(color) {
if (color.substr(0, 1) === '#') {
return color;
}
var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color);
var red = parseInt(digits[2]);
var green = parseInt(digits[3]);
var blue = parseInt(digits[4]);
var rgb = blue | (green << 8) | (red << 16);
return digits[1] + '#' + rgb.toString(16);
};
var icounter = 0;
Hitch.add([{
name: '-goat-tagCloud',
base: '[-goat-tagCloud]',
init: function(m){
var x, links, match, mId, h, w;
for(var i=0;i<m.length;i++){
match = m[i];
console.log('......' + computedStyle(match,'font-family'));
if(!match.id){ match.id = "data-goat-autocontainer-" + (icounter++); }
mId = 'data-goat-tagCloud-' + match.id;
w = computedStyle(match,'width');
h = computedStyle(match,'height');
if(!document.getElementById(mId)){
x = document.createElement('canvas');
x.height = (!isNaN(h)) ? parseInt(h) : 300;
x.width = (!isNaN(w)) ? parseInt(w) : 300;
x.id = mId;
match.appendChild(x);
TagCanvas.Start(
mId,
match.id,
{
weight: true,
weightFrom: 'data-goat-weight',
weightMode: match.getAttribute('data-goat-weightMode') || 'size',
zoomMin: match.getAttribute('data-goat-zoomMin') || '0.3',
zoomMax: match.getAttribute('data-goat-zoomMax') || '3.0',
wheelZoom: (match.getAttribute('data-goat-wheelZoom') !== null),
lock: match.getAttribute('data-goat-lock'),
textColour: colorToHex(computedStyle(match,'color')),
weightMultiplier: match.getAttribute('data-goat-weightSize') || '1.0',
freezeActive: (match.getAttribute('data-goat-freezeActive') !== null)
}
);
match.style.display = 'block';
links = match.querySelectorAll('a');
for(var i=0;i<links.length;i++){
links[i].style.display = "none";
}
}
};
},
fn: function(){}
}]);
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment