* | * should pop to 'tr', not the first 'td'
"""
nestingResetTriggers = self.NESTABLE_TAGS.get(name)
isNestable = nestingResetTriggers != None
isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
popTo = None
inclusive = True
for i in range(len(self.tagStack)-1, 0, -1):
p = self.tagStack[i]
if (not p or p.name == name) and not isNestable:
#Non-nestable tags get popped to the top or to their
#last occurance.
popTo = name
break
if (nestingResetTriggers is not None
and p.name in nestingResetTriggers) \
or (nestingResetTriggers is None and isResetNesting
and self.RESET_NESTING_TAGS.has_key(p.name)):
#If we encounter one of the nesting reset triggers
#peculiar to this tag, or we encounter another tag
#that causes nesting to reset, pop up to but not
#including that tag.
popTo = p.name
inclusive = False
break
p = p.parent
if popTo:
self._popToTag(popTo, inclusive)
def unknown_starttag(self, name, attrs, selfClosing=0):
#print "Start tag %s: %s" % (name, attrs)
if self.quoteStack:
#This is not a real tag.
#print "<%s> is not real!" % name
attrs = ''.join([' %s="%s"' % (x, y) for x, y in attrs])
self.handle_data('<%s%s>' % (name, attrs))
return
self.endData()
if not self.isSelfClosingTag(name) and not selfClosing:
self._smartPop(name)
if self.parseOnlyThese and len(self.tagStack) <= 1 \
and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)):
return
tag = Tag(self, name, attrs, self.currentTag, self.previous)
if self.previous:
self.previous.next = tag
self.previous = tag
self.pushTag(tag)
if selfClosing or self.isSelfClosingTag(name):
self.popTag()
if name in self.QUOTE_TAGS:
#print "Beginning quote (%s)" % name
self.quoteStack.append(name)
self.literal = 1
return tag
def unknown_endtag(self, name):
#print "End tag %s" % name
if self.quoteStack and self.quoteStack[-1] != name:
#This is not a real end tag.
#print "%s> is not real!" % name
self.handle_data('%s>' % name)
return
self.endData()
self._popToTag(name)
if self.quoteStack and self.quoteStack[-1] == name:
self.quoteStack.pop()
self.literal = (len(self.quoteStack) > 0)
def handle_data(self, data):
self.currentData.append(data)
def _toStringSubclass(self, text, subclass):
"""Adds a certain piece of text to the tree as a NavigableString
subclass."""
self.endData()
self.handle_data(text)
self.endData(subclass)
def handle_pi(self, text):
"""Handle a processing instruction as a ProcessingInstruction
object, possibly one with a %SOUP-ENCODING% slot into which an
encoding will be plugged later."""
if text[:3] == "xml":
text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"
self._toStringSubclass(text, ProcessingInstruction)
def handle_comment(self, text):
"Handle comments as Comment objects."
self._toStringSubclass(text, Comment)
def handle_charref(self, ref):
"Handle character references as data."
if self.convertEntities:
data = unichr(int(ref))
else:
data = '%s;' % ref
self.handle_data(data)
def handle_entityref(self, ref):
"""Handle entity references as data, possibly converting known
HTML and/or XML entity references to the corresponding Unicode
characters."""
data = None
if self.convertHTMLEntities:
try:
data = unichr(name2codepoint[ref])
except KeyError:
pass
if not data and self.convertXMLEntities:
data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref)
if not data and self.convertHTMLEntities and \
not self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref):
# TODO: We've got a problem here. We're told this is
# an entity reference, but it's not an XML entity
# reference or an HTML entity reference. Nonetheless,
# the logical thing to do is to pass it through as an
# unrecognized entity reference.
#
# Except: when the input is "&carol;" this function
# will be called with input "carol". When the input is
# "AT&T", this function will be called with input
# "T". We have no way of knowing whether a semicolon
# was present originally, so we don't know whether
# this is an unknown entity or just a misplaced
# ampersand.
#
# The more common case is a misplaced ampersand, so I
# escape the ampersand and omit the trailing semicolon.
data = "&%s" % ref
if not data:
# This case is different from the one above, because we
# haven't already gone through a supposedly comprehensive
# mapping of entities to Unicode characters. We might not
# have gone through any mapping at all. So the chances are
# very high that this is a real entity, and not a
# misplaced ampersand.
data = "&%s;" % ref
self.handle_data(data)
def handle_decl(self, data):
"Handle DOCTYPEs and the like as Declaration objects."
self._toStringSubclass(data, Declaration)
def parse_declaration(self, i):
"""Treat a bogus SGML declaration as raw data. Treat a CDATA
declaration as a CData object."""
j = None
if self.rawdata[i:i+9] == '', i)
if k == -1:
k = len(self.rawdata)
data = self.rawdata[i+9:k]
j = k+3
self._toStringSubclass(data, CData)
else:
try:
j = SGMLParser.parse_declaration(self, i)
except SGMLParseError:
toHandle = self.rawdata[i:]
self.handle_data(toHandle)
j = i + len(toHandle)
return j
class BeautifulSoup(BeautifulStoneSoup):
"""This parser knows the following facts about HTML:
* Some tags have no closing tag and should be interpreted as being
closed as soon as they are encountered.
* The text inside some tags (ie. 'script') may contain tags which
are not really part of the document and which should be parsed
as text, not tags. If you want to parse the text as tags, you can
always fetch it and parse it explicitly.
* Tag nesting rules:
Most tags can't be nested at all. For instance, the occurance of
a tag should implicitly close the previous tag.
Para1 Para2
should be transformed into:
Para1 Para2
Some tags can be nested arbitrarily. For instance, the occurance
of a tag should _not_ implicitly close the previous
tag.
Alice said: Bob said: Blah
should NOT be transformed into:
Alice said: Bob said: Blah
Some tags can be nested, but the nesting is reset by the
interposition of other tags. For instance, a tag should
implicitly close the previous tag within the same ,
but not close a tag in another table.
Blah Blah
should be transformed into:
Blah Blah
but,
BlahBlah
should NOT be transformed into
BlahBlah
Differing assumptions about tag nesting rules are a major source
of problems with the BeautifulSoup class. If BeautifulSoup is not
treating as nestable a tag your page author treats as nestable,
try ICantBelieveItsBeautifulSoup, MinimalSoup, or
BeautifulStoneSoup before writing your own subclass."""
def __init__(self, *args, **kwargs):
if not kwargs.has_key('smartQuotesTo'):
kwargs['smartQuotesTo'] = self.HTML_ENTITIES
kwargs['isHTML'] = True
BeautifulStoneSoup.__init__(self, *args, **kwargs)
SELF_CLOSING_TAGS = buildTagMap(None,
('br' , 'hr', 'input', 'img', 'meta',
'spacer', 'link', 'frame', 'base', 'col'))
PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea'])
QUOTE_TAGS = {'script' : None, 'textarea' : None}
#According to the HTML standard, each of these inline tags can
#contain another tag of the same type. Furthermore, it's common
#to actually use these tags this way.
NESTABLE_INLINE_TAGS = ('span', 'font', 'q', 'object', 'bdo', 'sub', 'sup',
'center')
#According to the HTML standard, these block tags can contain
#another tag of the same type. Furthermore, it's common
#to actually use these tags this way.
NESTABLE_BLOCK_TAGS = ('blockquote', 'div', 'fieldset', 'ins', 'del')
#Lists can contain other lists, but there are restrictions.
NESTABLE_LIST_TAGS = { 'ol' : [],
'ul' : [],
'li' : ['ul', 'ol'],
'dl' : [],
'dd' : ['dl'],
'dt' : ['dl'] }
#Tables can contain other tables, but there are restrictions.
NESTABLE_TABLE_TAGS = {'table' : [],
'tr' : ['table', 'tbody', 'tfoot', 'thead'],
'td' : ['tr'],
'th' : ['tr'],
'thead' : ['table'],
'tbody' : ['table'],
'tfoot' : ['table'],
}
NON_NESTABLE_BLOCK_TAGS = ('address', 'form', 'p', 'pre')
#If one of these tags is encountered, all tags up to the next tag of
#this type are popped.
RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript',
NON_NESTABLE_BLOCK_TAGS,
NESTABLE_LIST_TAGS,
NESTABLE_TABLE_TAGS)
NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS,
NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
# Used to detect the charset in a META tag; see start_meta
CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M)
def start_meta(self, attrs):
"""Beautiful Soup can detect a charset included in a META tag,
try to convert the document to that charset, and re-parse the
document from the beginning."""
httpEquiv = None
contentType = None
contentTypeIndex = None
tagNeedsEncodingSubstitution = False
for i in range(0, len(attrs)):
key, value = attrs[i]
key = key.lower()
if key == 'http-equiv':
httpEquiv = value
elif key == 'content':
contentType = value
contentTypeIndex = i
if httpEquiv and contentType: # It's an interesting meta tag.
match = self.CHARSET_RE.search(contentType)
if match:
if (self.declaredHTMLEncoding is not None or
self.originalEncoding == self.fromEncoding):
# An HTML encoding was sniffed while converting
# the document to Unicode, or an HTML encoding was
# sniffed during a previous pass through the
# document, or an encoding was specified
# explicitly and it worked. Rewrite the meta tag.
def rewrite(match):
return match.group(1) + "%SOUP-ENCODING%"
newAttr = self.CHARSET_RE.sub(rewrite, contentType)
attrs[contentTypeIndex] = (attrs[contentTypeIndex][0],
newAttr)
tagNeedsEncodingSubstitution = True
else:
# This is our first pass through the document.
# Go through it again with the encoding information.
newCharset = match.group(3)
if newCharset and newCharset != self.originalEncoding:
self.declaredHTMLEncoding = newCharset
self._feed(self.declaredHTMLEncoding)
raise StopParsing
pass
tag = self.unknown_starttag("meta", attrs)
if tag and tagNeedsEncodingSubstitution:
tag.containsSubstitutions = True
class StopParsing(Exception):
pass
class ICantBelieveItsBeautifulSoup(BeautifulSoup):
"""The BeautifulSoup class is oriented towards skipping over
common HTML errors like unclosed tags. However, sometimes it makes
errors of its own. For instance, consider this fragment:
FooBar
This is perfectly valid (if bizarre) HTML. However, the
BeautifulSoup class will implicitly close the first b tag when it
encounters the second 'b'. It will think the author wrote
"FooBar", and didn't close the first 'b' tag, because
there's no real-world reason to bold something that's already
bold. When it encounters '' it will close two more 'b'
tags, for a grand total of three tags closed instead of two. This
can throw off the rest of your document structure. The same is
true of a number of other tags, listed below.
It's much more common for someone to forget to close a 'b' tag
than to actually use nested 'b' tags, and the BeautifulSoup class
handles the common case. This class handles the not-co-common
case: where you can't believe someone wrote what they did, but
it's valid HTML and BeautifulSoup screwed up by assuming it
wouldn't be."""
I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \
('em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong',
'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b',
'big')
I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ('noscript')
NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS,
I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS,
I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS)
class MinimalSoup(BeautifulSoup):
"""The MinimalSoup class is for parsing HTML that contains
pathologically bad markup. It makes no assumptions about tag
nesting, but it does know which tags are self-closing, that
wapiti-2.2.1/src/report_template/includes/js/wz_jsgraphics.js 0000644 0000000 0000000 00000055745 11064471200 023154 0 ustar root root /* This notice must be untouched at all times.
wz_jsgraphics.js v. 3.00
The latest version is available at
http://www.walterzorn.com
or http://www.devira.com
or http://www.walterzorn.de
Copyright (c) 2002-2004 Walter Zorn. All rights reserved.
Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )
Last modified: 4. 2. 2007
Performance optimizations for Internet Explorer
by Thomas Frank and John Holdsworth.
fillPolygon method implemented by Matthieu Haller.
High Performance JavaScript Graphics Library.
Provides methods
- to draw lines, rectangles, ellipses, polygons
with specifiable line thickness,
- to fill rectangles, polygons, ellipses and arcs
- to draw text.
NOTE: Operations, functions and branching have rather been optimized
to efficiency and speed than to shortness of source code.
LICENSE: LGPL
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License (LGPL) as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
or see http://www.gnu.org/copyleft/lesser.html
*/
var jg_ok, jg_ie, jg_fast, jg_dom, jg_moz;
function chkDHTM(x, i)
{
x = document.body || null;
jg_ie = x && typeof x.insertAdjacentHTML != "undefined" && document.createElement;
jg_dom = (x && !jg_ie &&
typeof x.appendChild != "undefined" &&
typeof document.createRange != "undefined" &&
typeof (i = document.createRange()).setStartBefore != "undefined" &&
typeof i.createContextualFragment != "undefined");
jg_fast = jg_ie && document.all && !window.opera;
jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";
jg_ok = !!(jg_ie || jg_dom);
}
function pntCnvDom()
{
var x = this.wnd.document.createRange();
x.setStartBefore(this.cnv);
x = x.createContextualFragment(jg_fast? this.htmRpc() : this.htm);
if(this.cnv) this.cnv.appendChild(x);
this.htm = "";
}
function pntCnvIe()
{
if(this.cnv) this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this.htmRpc() : this.htm);
this.htm = "";
}
function pntDoc()
{
this.wnd.document.write(jg_fast? this.htmRpc() : this.htm);
this.htm = '';
}
function pntN()
{
;
}
function mkDiv(x, y, w, h)
{
this.htm += '<\/div>';
}
function mkDivIe(x, y, w, h)
{
this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';
}
function mkDivPrt(x, y, w, h)
{
this.htm += ' <\/div>';
}
var regex = /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;
function htmRpc()
{
return this.htm.replace(
regex,
' \n');
}
function htmPrtRpc()
{
return this.htm.replace(
regex,
' \n');
}
function mkLin(x1, y1, x2, y2)
{
if(x1 > x2)
{
var _x2 = x2;
var _y2 = y2;
x2 = x1;
y2 = y1;
x1 = _x2;
y1 = _y2;
}
var dx = x2-x1, dy = Math.abs(y2-y1),
x = x1, y = y1,
yIncr = (y1 > y2)? -1 : 1;
if(dx >= dy)
{
var pr = dy<<1,
pru = pr - (dx<<1),
p = pr-dx,
ox = x;
while(dx > 0)
{--dx;
++x;
if(p > 0)
{
this.mkDiv(ox, y, x-ox, 1);
y += yIncr;
p += pru;
ox = x;
}
else p += pr;
}
this.mkDiv(ox, y, x2-ox+1, 1);
}
else
{
var pr = dx<<1,
pru = pr - (dy<<1),
p = pr-dy,
oy = y;
if(y2 <= y1)
{
while(dy > 0)
{--dy;
if(p > 0)
{
this.mkDiv(x++, y, 1, oy-y+1);
y += yIncr;
p += pru;
oy = y;
}
else
{
y += yIncr;
p += pr;
}
}
this.mkDiv(x2, y2, 1, oy-y2+1);
}
else
{
while(dy > 0)
{--dy;
y += yIncr;
if(p > 0)
{
this.mkDiv(x++, oy, 1, y-oy);
p += pru;
oy = y;
}
else p += pr;
}
this.mkDiv(x2, oy, 1, y2-oy+1);
}
}
}
function mkLin2D(x1, y1, x2, y2)
{
if(x1 > x2)
{
var _x2 = x2;
var _y2 = y2;
x2 = x1;
y2 = y1;
x1 = _x2;
y1 = _y2;
}
var dx = x2-x1, dy = Math.abs(y2-y1),
x = x1, y = y1,
yIncr = (y1 > y2)? -1 : 1;
var s = this.stroke;
if(dx >= dy)
{
if(dx > 0 && s-3 > 0)
{
var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;
_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
}
else var _s = s;
var ad = Math.ceil(s/2);
var pr = dy<<1,
pru = pr - (dx<<1),
p = pr-dx,
ox = x;
while(dx > 0)
{--dx;
++x;
if(p > 0)
{
this.mkDiv(ox, y, x-ox+ad, _s);
y += yIncr;
p += pru;
ox = x;
}
else p += pr;
}
this.mkDiv(ox, y, x2-ox+ad+1, _s);
}
else
{
if(s-3 > 0)
{
var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;
_s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;
}
else var _s = s;
var ad = Math.round(s/2);
var pr = dx<<1,
pru = pr - (dy<<1),
p = pr-dy,
oy = y;
if(y2 <= y1)
{
++ad;
while(dy > 0)
{--dy;
if(p > 0)
{
this.mkDiv(x++, y, _s, oy-y+ad);
y += yIncr;
p += pru;
oy = y;
}
else
{
y += yIncr;
p += pr;
}
}
this.mkDiv(x2, y2, _s, oy-y2+ad);
}
else
{
while(dy > 0)
{--dy;
y += yIncr;
if(p > 0)
{
this.mkDiv(x++, oy, _s, y-oy+ad);
p += pru;
oy = y;
}
else p += pr;
}
this.mkDiv(x2, oy, _s, y2-oy+ad+1);
}
}
}
function mkLinDott(x1, y1, x2, y2)
{
if(x1 > x2)
{
var _x2 = x2;
var _y2 = y2;
x2 = x1;
y2 = y1;
x1 = _x2;
y1 = _y2;
}
var dx = x2-x1, dy = Math.abs(y2-y1),
x = x1, y = y1,
yIncr = (y1 > y2)? -1 : 1,
drw = true;
if(dx >= dy)
{
var pr = dy<<1,
pru = pr - (dx<<1),
p = pr-dx;
while(dx > 0)
{--dx;
if(drw) this.mkDiv(x, y, 1, 1);
drw = !drw;
if(p > 0)
{
y += yIncr;
p += pru;
}
else p += pr;
++x;
}
}
else
{
var pr = dx<<1,
pru = pr - (dy<<1),
p = pr-dy;
while(dy > 0)
{--dy;
if(drw) this.mkDiv(x, y, 1, 1);
drw = !drw;
y += yIncr;
if(p > 0)
{
++x;
p += pru;
}
else p += pr;
}
}
if(drw) this.mkDiv(x, y, 1, 1);
}
function mkOv(left, top, width, height)
{
var a = (++width)>>1, b = (++height)>>1,
wod = width&1, hod = height&1,
cx = left+a, cy = top+b,
x = 0, y = b,
ox = 0, oy = b,
aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
st = (aa2>>1)*(1-(b<<1)) + bb2,
tt = (bb2>>1) - aa2*((b<<1)-1),
w, h;
while(y > 0)
{
if(st < 0)
{
st += bb2*((x<<1)+3);
tt += bb4*(++x);
}
else if(tt < 0)
{
st += bb2*((x<<1)+3) - aa4*(y-1);
tt += bb4*(++x) - aa2*(((y--)<<1)-3);
w = x-ox;
h = oy-y;
if((w&2) && (h&2))
{
this.mkOvQds(cx, cy, x-2, y+2, 1, 1, wod, hod);
this.mkOvQds(cx, cy, x-1, y+1, 1, 1, wod, hod);
}
else this.mkOvQds(cx, cy, x-1, oy, w, h, wod, hod);
ox = x;
oy = y;
}
else
{
tt -= aa2*((y<<1)-3);
st -= aa4*(--y);
}
}
w = a-ox+1;
h = (oy<<1)+hod;
y = cy-oy;
this.mkDiv(cx-a, y, w, h);
this.mkDiv(cx+ox+wod-1, y, w, h);
}
function mkOv2D(left, top, width, height)
{
var s = this.stroke;
width += s+1;
height += s+1;
var a = width>>1, b = height>>1,
wod = width&1, hod = height&1,
cx = left+a, cy = top+b,
x = 0, y = b,
aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
st = (aa2>>1)*(1-(b<<1)) + bb2,
tt = (bb2>>1) - aa2*((b<<1)-1);
if(s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))
{
var ox = 0, oy = b,
w, h,
pxw;
while(y > 0)
{
if(st < 0)
{
st += bb2*((x<<1)+3);
tt += bb4*(++x);
}
else if(tt < 0)
{
st += bb2*((x<<1)+3) - aa4*(y-1);
tt += bb4*(++x) - aa2*(((y--)<<1)-3);
w = x-ox;
h = oy-y;
if(w-1)
{
pxw = w+1+(s&1);
h = s;
}
else if(h-1)
{
pxw = s;
h += 1+(s&1);
}
else pxw = h = s;
this.mkOvQds(cx, cy, x-1, oy, pxw, h, wod, hod);
ox = x;
oy = y;
}
else
{
tt -= aa2*((y<<1)-3);
st -= aa4*(--y);
}
}
this.mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);
this.mkDiv(cx+a+wod-s, cy-oy, s, (oy<<1)+hod);
}
else
{
var _a = (width-(s<<1))>>1,
_b = (height-(s<<1))>>1,
_x = 0, _y = _b,
_aa2 = (_a*_a)<<1, _aa4 = _aa2<<1, _bb2 = (_b*_b)<<1, _bb4 = _bb2<<1,
_st = (_aa2>>1)*(1-(_b<<1)) + _bb2,
_tt = (_bb2>>1) - _aa2*((_b<<1)-1),
pxl = new Array(),
pxt = new Array(),
_pxb = new Array();
pxl[0] = 0;
pxt[0] = b;
_pxb[0] = _b-1;
while(y > 0)
{
if(st < 0)
{
pxl[pxl.length] = x;
pxt[pxt.length] = y;
st += bb2*((x<<1)+3);
tt += bb4*(++x);
}
else if(tt < 0)
{
pxl[pxl.length] = x;
st += bb2*((x<<1)+3) - aa4*(y-1);
tt += bb4*(++x) - aa2*(((y--)<<1)-3);
pxt[pxt.length] = y;
}
else
{
tt -= aa2*((y<<1)-3);
st -= aa4*(--y);
}
if(_y > 0)
{
if(_st < 0)
{
_st += _bb2*((_x<<1)+3);
_tt += _bb4*(++_x);
_pxb[_pxb.length] = _y-1;
}
else if(_tt < 0)
{
_st += _bb2*((_x<<1)+3) - _aa4*(_y-1);
_tt += _bb4*(++_x) - _aa2*(((_y--)<<1)-3);
_pxb[_pxb.length] = _y-1;
}
else
{
_tt -= _aa2*((_y<<1)-3);
_st -= _aa4*(--_y);
_pxb[_pxb.length-1]--;
}
}
}
var ox = -wod, oy = b,
_oy = _pxb[0],
l = pxl.length,
w, h;
for(var i = 0; i < l; i++)
{
if(typeof _pxb[i] != "undefined")
{
if(_pxb[i] < _oy || pxt[i] < oy)
{
x = pxl[i];
this.mkOvQds(cx, cy, x, oy, x-ox, oy-_oy, wod, hod);
ox = x;
oy = pxt[i];
_oy = _pxb[i];
}
}
else
{
x = pxl[i];
this.mkDiv(cx-x, cy-oy, 1, (oy<<1)+hod);
this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
ox = x;
oy = pxt[i];
}
}
this.mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);
this.mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);
}
}
function mkOvDott(left, top, width, height)
{
var a = (++width)>>1, b = (++height)>>1,
wod = width&1, hod = height&1, hodu = hod^1,
cx = left+a, cy = top+b,
x = 0, y = b,
aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
st = (aa2>>1)*(1-(b<<1)) + bb2,
tt = (bb2>>1) - aa2*((b<<1)-1),
drw = true;
while(y > 0)
{
if(st < 0)
{
st += bb2*((x<<1)+3);
tt += bb4*(++x);
}
else if(tt < 0)
{
st += bb2*((x<<1)+3) - aa4*(y-1);
tt += bb4*(++x) - aa2*(((y--)<<1)-3);
}
else
{
tt -= aa2*((y<<1)-3);
st -= aa4*(--y);
}
if(drw && y >= hodu) this.mkOvQds(cx, cy, x, y, 1, 1, wod, hod);
drw = !drw;
}
}
function mkRect(x, y, w, h)
{
var s = this.stroke;
this.mkDiv(x, y, w, s);
this.mkDiv(x+w, y, s, h);
this.mkDiv(x, y+h, w+s, s);
this.mkDiv(x, y+s, s, h-s);
}
function mkRectDott(x, y, w, h)
{
this.drawLine(x, y, x+w, y);
this.drawLine(x+w, y, x+w, y+h);
this.drawLine(x, y+h, x+w, y+h);
this.drawLine(x, y, x, y+h);
}
function jsgFont()
{
this.PLAIN = 'font-weight:normal;';
this.BOLD = 'font-weight:bold;';
this.ITALIC = 'font-style:italic;';
this.ITALIC_BOLD = this.ITALIC + this.BOLD;
this.BOLD_ITALIC = this.ITALIC_BOLD;
}
var Font = new jsgFont();
function jsgStroke()
{
this.DOTTED = -1;
}
var Stroke = new jsgStroke();
function jsGraphics(cnv, wnd)
{
this.setColor = new Function('arg', 'this.color = arg.toLowerCase();');
this.setStroke = function(x)
{
this.stroke = x;
if(!(x+1))
{
this.drawLine = mkLinDott;
this.mkOv = mkOvDott;
this.drawRect = mkRectDott;
}
else if(x-1 > 0)
{
this.drawLine = mkLin2D;
this.mkOv = mkOv2D;
this.drawRect = mkRect;
}
else
{
this.drawLine = mkLin;
this.mkOv = mkOv;
this.drawRect = mkRect;
}
};
this.setPrintable = function(arg)
{
this.printable = arg;
if(jg_fast)
{
this.mkDiv = mkDivIe;
this.htmRpc = arg? htmPrtRpc : htmRpc;
}
else this.mkDiv = arg? mkDivPrt : mkDiv;
};
this.setFont = function(fam, sz, sty)
{
this.ftFam = fam;
this.ftSz = sz;
this.ftSty = sty || Font.PLAIN;
};
this.drawPolyline = this.drawPolyLine = function(x, y)
{
for (var i=x.length - 1; i;)
{--i;
this.drawLine(x[i], y[i], x[i+1], y[i+1]);
}
};
this.fillRect = function(x, y, w, h)
{
this.mkDiv(x, y, w, h);
};
this.drawPolygon = function(x, y)
{
this.drawPolyline(x, y);
this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);
};
this.drawEllipse = this.drawOval = function(x, y, w, h)
{
this.mkOv(x, y, w, h);
};
this.fillEllipse = this.fillOval = function(left, top, w, h)
{
var a = w>>1, b = h>>1,
wod = w&1, hod = h&1,
cx = left+a, cy = top+b,
x = 0, y = b, oy = b,
aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
st = (aa2>>1)*(1-(b<<1)) + bb2,
tt = (bb2>>1) - aa2*((b<<1)-1),
xl, dw, dh;
if(w) while(y > 0)
{
if(st < 0)
{
st += bb2*((x<<1)+3);
tt += bb4*(++x);
}
else if(tt < 0)
{
st += bb2*((x<<1)+3) - aa4*(y-1);
xl = cx-x;
dw = (x<<1)+wod;
tt += bb4*(++x) - aa2*(((y--)<<1)-3);
dh = oy-y;
this.mkDiv(xl, cy-oy, dw, dh);
this.mkDiv(xl, cy+y+hod, dw, dh);
oy = y;
}
else
{
tt -= aa2*((y<<1)-3);
st -= aa4*(--y);
}
}
this.mkDiv(cx-a, cy-oy, w, (oy<<1)+hod);
};
this.fillArc = function(iL, iT, iW, iH, fAngA, fAngZ)
{
var a = iW>>1, b = iH>>1,
iOdds = (iW&1) | ((iH&1) << 16),
cx = iL+a, cy = iT+b,
x = 0, y = b, ox = x, oy = y,
aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,
st = (aa2>>1)*(1-(b<<1)) + bb2,
tt = (bb2>>1) - aa2*((b<<1)-1),
// Vars for radial boundary lines
xEndA, yEndA, xEndZ, yEndZ,
iSects = (1 << (Math.floor((fAngA %= 360.0)/180.0) << 3))
| (2 << (Math.floor((fAngZ %= 360.0)/180.0) << 3))
| ((fAngA >= fAngZ) << 16),
aBndA = new Array(b+1), aBndZ = new Array(b+1);
// Set up radial boundary lines
fAngA *= Math.PI/180.0;
fAngZ *= Math.PI/180.0;
xEndA = cx+Math.round(a*Math.cos(fAngA));
yEndA = cy+Math.round(-b*Math.sin(fAngA));
aBndA.mkLinVirt(cx, cy, xEndA, yEndA);
xEndZ = cx+Math.round(a*Math.cos(fAngZ));
yEndZ = cy+Math.round(-b*Math.sin(fAngZ));
aBndZ.mkLinVirt(cx, cy, xEndZ, yEndZ);
while(y > 0)
{
if(st < 0) // Advance x
{
st += bb2*((x<<1)+3);
tt += bb4*(++x);
}
else if(tt < 0) // Advance x and y
{
st += bb2*((x<<1)+3) - aa4*(y-1);
ox = x;
tt += bb4*(++x) - aa2*(((y--)<<1)-3);
this.mkArcDiv(ox, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
oy = y;
}
else // Advance y
{
tt -= aa2*((y<<1)-3);
st -= aa4*(--y);
if(y && (aBndA[y] != aBndA[y-1] || aBndZ[y] != aBndZ[y-1]))
{
this.mkArcDiv(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
ox = x;
oy = y;
}
}
}
this.mkArcDiv(x, 0, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);
if(iOdds >> 16) // Odd height
{
if(iSects >> 16) // Start-angle > end-angle
{
var xl = (yEndA <= cy || yEndZ > cy)? (cx - x) : cx;
this.mkDiv(xl, cy, x + cx - xl + (iOdds & 0xffff), 1);
}
else if((iSects & 0x01) && yEndZ > cy)
this.mkDiv(cx - x, cy, x, 1);
}
};
/* fillPolygon method, implemented by Matthieu Haller.
This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.
C source of GD 1.8.4 found at http://www.boutell.com/gd/
THANKS to Kirsten Schulz for the polygon fixes!
The intersection finding technique of this code could be improved
by remembering the previous intertersection, and by using the slope.
That could help to adjust intersections to produce a nice
interior_extrema. */
this.fillPolygon = function(array_x, array_y)
{
var i;
var y;
var miny, maxy;
var x1, y1;
var x2, y2;
var ind1, ind2;
var ints;
var n = array_x.length;
if(!n) return;
miny = array_y[0];
maxy = array_y[0];
for(i = 1; i < n; i++)
{
if(array_y[i] < miny)
miny = array_y[i];
if(array_y[i] > maxy)
maxy = array_y[i];
}
for(y = miny; y <= maxy; y++)
{
var polyInts = new Array();
ints = 0;
for(i = 0; i < n; i++)
{
if(!i)
{
ind1 = n-1;
ind2 = 0;
}
else
{
ind1 = i-1;
ind2 = i;
}
y1 = array_y[ind1];
y2 = array_y[ind2];
if(y1 < y2)
{
x1 = array_x[ind1];
x2 = array_x[ind2];
}
else if(y1 > y2)
{
y2 = array_y[ind1];
y1 = array_y[ind2];
x2 = array_x[ind1];
x1 = array_x[ind2];
}
else continue;
// Modified 11. 2. 2004 Walter Zorn
if((y >= y1) && (y < y2))
polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
else if((y == maxy) && (y > y1) && (y <= y2))
polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);
}
polyInts.sort(CompInt);
for(i = 0; i < ints; i+=2)
this.mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);
}
};
this.drawString = function(txt, x, y)
{
this.htm += ' '+
txt +
'<\/div>';
};
/* drawStringRect() added by Rick Blommers.
Allows to specify the size of the text rectangle and to align the
text both horizontally (e.g. right) and vertically within that rectangle */
this.drawStringRect = function(txt, x, y, width, halign)
{
this.htm += ' '+
txt +
'<\/div>';
};
this.drawImage = function(imgSrc, x, y, w, h, a)
{
this.htm += ' '+
'  '+
'<\/div>';
};
this.clear = function()
{
this.htm = "";
if(this.cnv) this.cnv.innerHTML = "";
};
this.mkOvQds = function(cx, cy, x, y, w, h, wod, hod)
{
var xl = cx - x, xr = cx + x + wod - w, yt = cy - y, yb = cy + y + hod - h;
if(xr > xl+w)
{
this.mkDiv(xr, yt, w, h);
this.mkDiv(xr, yb, w, h);
}
else
w = xr - xl + w;
this.mkDiv(xl, yt, w, h);
this.mkDiv(xl, yb, w, h);
};
this.mkArcDiv = function(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects)
{
var xrDef = cx + x + (iOdds & 0xffff), y2, h = oy - y, xl, xr, w;
if(!h) h = 1;
x = cx - x;
if(iSects & 0xff0000) // Start-angle > end-angle
{
y2 = cy - y - h;
if(iSects & 0x00ff)
{
if(iSects & 0x02)
{
xl = Math.max(x, aBndZ[y]);
w = xrDef - xl;
if(w > 0) this.mkDiv(xl, y2, w, h);
}
if(iSects & 0x01)
{
xr = Math.min(xrDef, aBndA[y]);
w = xr - x;
if(w > 0) this.mkDiv(x, y2, w, h);
}
}
else
this.mkDiv(x, y2, xrDef - x, h);
y2 = cy + y + (iOdds >> 16);
if(iSects & 0xff00)
{
if(iSects & 0x0100)
{
xl = Math.max(x, aBndA[y]);
w = xrDef - xl;
if(w > 0) this.mkDiv(xl, y2, w, h);
}
if(iSects & 0x0200)
{
xr = Math.min(xrDef, aBndZ[y]);
w = xr - x;
if(w > 0) this.mkDiv(x, y2, w, h);
}
}
else
this.mkDiv(x, y2, xrDef - x, h);
}
else
{
if(iSects & 0x00ff)
{
if(iSects & 0x02)
xl = Math.max(x, aBndZ[y]);
else
xl = x;
if(iSects & 0x01)
xr = Math.min(xrDef, aBndA[y]);
else
xr = xrDef;
y2 = cy - y - h;
w = xr - xl;
if(w > 0) this.mkDiv(xl, y2, w, h);
}
if(iSects & 0xff00)
{
if(iSects & 0x0100)
xl = Math.max(x, aBndA[y]);
else
xl = x;
if(iSects & 0x0200)
xr = Math.min(xrDef, aBndZ[y]);
else
xr = xrDef;
y2 = cy + y + (iOdds >> 16);
w = xr - xl;
if(w > 0) this.mkDiv(xl, y2, w, h);
}
}
};
this.setStroke(1);
this.setFont("verdana,geneva,helvetica,sans-serif", "12px", Font.PLAIN);
this.color = "#000000";
this.htm = "";
this.wnd = wnd || window;
if(!jg_ok) chkDHTM();
if(jg_ok)
{
if(cnv)
{
if(typeof(cnv) == "string")
this.cont = document.all? (this.wnd.document.all[cnv] || null)
: document.getElementById? (this.wnd.document.getElementById(cnv) || null)
: null;
else if(cnv == window.document)
this.cont = document.getElementsByTagName("body")[0];
// If cnv is a direct reference to a canvas DOM node
// (option suggested by Andreas Luleich)
else this.cont = cnv;
// Create new canvas inside container DIV. Thus the drawing and clearing
// methods won't interfere with the container's inner html.
// Solution suggested by Vladimir.
this.cnv = document.createElement("div");
this.cont.appendChild(this.cnv);
this.paint = jg_dom? pntCnvDom : pntCnvIe;
}
else
this.paint = pntDoc;
}
else
this.paint = pntN;
this.setPrintable(false);
}
Array.prototype.mkLinVirt = function(x1, y1, x2, y2)
{
var dx = Math.abs(x2-x1), dy = Math.abs(y2-y1),
x = x1, y = y1,
xIncr = (x1 > x2)? -1 : 1,
yIncr = (y1 > y2)? -1 : 1,
p,
i = 0;
if(dx >= dy)
{
var pr = dy<<1,
pru = pr - (dx<<1);
p = pr-dx;
while(dx > 0)
{--dx;
if(p > 0) // Increment y
{
this[i++] = x;
y += yIncr;
p += pru;
}
else p += pr;
x += xIncr;
}
}
else
{
var pr = dx<<1,
pru = pr - (dy<<1);
p = pr-dy;
while(dy > 0)
{--dy;
y += yIncr;
this[i++] = x;
if(p > 0) // Increment x
{
x += xIncr;
p += pru;
}
else p += pr;
}
}
for(var len = this.length, i = len-i; i;)
this[len-(i--)] = x;
};
function CompInt(x, y)
{
return(x - y);
}
wapiti-2.2.1/src/report_template/includes/js/piechart.js 0000644 0000000 0000000 00000056106 11064471200 022066 0 ustar root root /*----------------------------------------------------------------------------\
| Chart 1.0 |
|-----------------------------------------------------------------------------|
| Created by Emil A Eklund |
| (http://eae.net/contact/emil) |
|-----------------------------------------------------------------------------|
| Client side chart painter, supports line, area and bar charts and stacking, |
| uses Canvas (mozilla, safari, opera) or SVG (mozilla, opera) for drawing. |
| Can be used with IECanvas to allow the canvas painter to be used in IE. |
|-----------------------------------------------------------------------------|
| Copyright (c) 2006 Emil A Eklund |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
| This program is free software; you can redistribute it and/or modify it |
| under the terms of the MIT License. |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
| Permission is hereby granted, free of charge, to any person obtaining a |
| copy of this software and associated documentation files (the "Software"), |
| to deal in the Software without restriction, including without limitation |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| and/or sell copies of the Software, and to permit persons to whom the |
| Software is furnished to do so, subject to the following conditions: |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| DEALINGS IN THE SOFTWARE. |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
| http://eae.net/license/mit |
|-----------------------------------------------------------------------------|
| Dependencies: canvaschartpainter.js - Canvas chart painter implementation. |
| canvaschart.css - Canvas chart painter styles. |
| or: svgchartpainter.js - SVG chart painter implementation. |
|-----------------------------------------------------------------------------|
| 2006-01-03 | Work started. |
| 2006-01-05 | Added legend and axis labels. Changed the painter api slightly |
| | to allow two-stage initialization (required for ie/canvas) and |
| | added legend/axis related methods. Also updated bar chart type |
| | and added a few options, mostly related to bar charts. |
| 2006-01-07 | Updated chart size calculations to take legend and axis labels |
| | into consideration. Split painter implementations to separate |
| | files. |
| 2006-01-10 | Fixed bug in automatic range calculation. Also added explicit |
| | cast to float for stacked series. |
| 2006-04-16 | Updated constructor to set painter factory based on available |
| | and supported implementations. |
| 2007-02-01 | Brought chart related methods of PainterFactory classes into |
| | the Chart class, and reduced PainterFactory to simpler drawing |
| | primitives only. (by Ashutosh Bijoor -bijoor@gmail.com) |
|-----------------------------------------------------------------------------|
| Created 2006-01-03 | All changes are in the log above. | Updated 2007-02-01 |
\----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------\
| Chart |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
| Chart class, control class that's used to represent a chart. Uses a painter |
| class for the actual drawing. This is the only class that should be used |
| directly, the other ones are internal. |
\----------------------------------------------------------------------------*/
function Chart(el) {
this._cont = el;
this._yMin = null;
this._yMax = null;
this._xGridDensity = 0;
this._yGridDensity = 0;
this._flags = 0;
this._series = new Array();
this._labelPrecision = 0;
this._horizontalLabels = new Array();
this._barWidth = 10;
this._barDistance = 2;
this._bars = 0;
this._showLegend = true;
this._painter = null;
/*
* Determine painter implementation to use based on what's available and
* supported. CanvasChartPainter is the prefered one, JsGraphicsChartPainter
* the fallback one as it works in pretty much any browser. The
* SVGChartPainter implementation one will only be used if set explicitly as
* it's not up to pair with the other ones.
*/
if ((typeof CanvasChartPainterFactory != 'undefined') && (window.CanvasRenderingContext2D)) {
this.setPainterFactory(CanvasChartPainterFactory);
}
else if (typeof JsGraphicsChartPainterFactory != 'undefined') {
this.setPainterFactory(JsGraphicsChartPainterFactory);
}
else { this._painterFactory = null; }
}
Chart.prototype.setPainterFactory = function(f) {
this._painterFactory = f;
/* Create painter object */
this._painter = this._painterFactory();
this._painter.create(this._cont);
};
Chart.prototype.getPainter = function() {
return this._painter;
};
Chart.prototype.setVerticalRange = function(min, max) {
this._yMin = min;
this._yMax = max;
};
Chart.prototype.setLabelPrecision = function(precision) {
this._labelPrecision = precision;
};
Chart.prototype.setShowLegend = function(b) {
this._showLegend = b;
};
Chart.prototype.setGridDensity = function(horizontal, vertical) {
this._xGridDensity = horizontal;
this._yGridDensity = vertical;
};
Chart.prototype.setHorizontalLabels = function(labels) {
this._horizontalLabels = labels;
};
Chart.prototype.add = function(series) {
this._series.push(series);
};
Chart.prototype.draw = function() {
var i, o, o2, len, xlen, ymin, ymax, type, self, bLabels;
if (!this._painter) { return; }
/* Initialize */
this.xlen = 0;
this.ymin = this._yMin;
this.ymax = this._yMax;
/* Determine maximum number of values, ymin and ymax */
for (i = 0; i < this._series.length; i++) {
this._series[i].setRange(this);
}
/*
* For bar only charts the number of charts is the same as the length of the
* longest series, for others combinations it's one less. Compensate for that
* for bar only charts.
*/
//if (this._series.length == this._bars) {
this.xlen++;
this._xGridDensity++;
//}
/*
* Determine whatever or not to show the legend and axis labels
* Requires density and labels to be set.
*/
//bLabels = ((this._xGridDensity) && (this._yGridDensity) && (this._horizontalLabels.length >= this._xGridDensity));
bLabels = (this._xGridDensity) && (this._yGridDensity);
/* Initialize painter object */
this.init(this.xlen, this.ymin, this.ymax, this._xGridDensity, this._yGridDensity, bLabels);
/* Draw chart background */
this.drawBackground();
/*
* If labels and grid density where specified, draw legend and labels.
* It's drawn prior to the chart as the size of the legend and labels
* affects the size of the chart area.
*/
if (this._showLegend) { this.drawLegend(); }
if (bLabels) {
this.drawVerticalAxis(this._yGridDensity, this._labelPrecision);
this.drawHorizontalAxis(this.xlen, this._horizontalLabels, this._xGridDensity, this._labelPrecision);
}
/* Draw grid */
this.drawGrid();
/* Draw series */
for (i = 0; i < this._series.length; i++) {
this._series[i].draw(this);
}
/*
* Draw axis (after the series since the anti aliasing of the lines may
* otherwise be drawn on top of the axis)
*/
this.drawAxis();
};
Chart.prototype.init = function(xlen, ymin, ymax, xgd, ygd, bLegendLabels) {
this.w=this._painter.getWidth();
this.h=this._painter.getHeight();
this.chartx = 0;
this.chartw = this.w;
this.charth = this.h;
this.charty = 0;
this.xlen = xlen;
this.ymin = ymin;
this.ymax = ymax;
this.xgd = xgd;
this.ygd = ygd;
this.calc(this.chartw, this.charth, xlen, ymin, ymax, xgd, ygd);
};
Chart.prototype.calc = function(w, h, xlen, ymin, ymax, xgd, ygd) {
this.range = ymax - ymin;
this.xstep = w / (xlen - 1);
this.xgrid = (xgd)?w / (xgd - 1):0;
this.ygrid = (ygd)?h / (ygd - 1):0;
this.ymin = ymin;
this.ymax = ymax;
};
Chart.prototype.findSeries = function(label) {
for (var i = 0; i < this._series.length; i++) {
if (this._series[i].getLabel()==label) {
return this._series[i];
}
}
return null;
};
Chart.prototype.drawLegend = function() {
var legend, list, item, label;
var series=this._series;
legend = document.createElement('div');
legend.className = 'legend';
legend.style.position = 'absolute';
list = document.createElement('ul');
for (i = 0; i < series.length; i++) {
item = document.createElement('li');
item.style.color = series[i].getColor();
label = document.createElement('span');
label.appendChild(document.createTextNode(series[i].getLabel()));
label.style.color = 'black';
item.appendChild(label);
list.appendChild(item);
}
legend.appendChild(list);
this._cont.appendChild(legend);
legend.style.right = '0px';
legend.style.top = this.charty + (this.charth / 2) - (legend.offsetHeight / 2) + 'px';
this.legend = legend;
/* Recalculate chart width and position based on labels and legend */
this.chartw = this.w - (this.legend.offsetWidth + 5);
this.calc(this.chartw, this.charth, this.xlen, this.ymin, this.ymax, this.xgd, this.ygd);
};
Chart.prototype.drawVerticalAxis = function(ygd, precision) {
var axis, item, step, y, ty, n, yoffset, value, multiplier, w, items, pos;
/* Calculate step size and rounding precision */
multiplier = Math.pow(10, precision);
step = this.range / (ygd - 1);
/* Create container */
axis = document.createElement('div');
axis.style.position = 'absolute';
axis.style.left = '0px';
axis.style.top = '0px';
axis.style.textAlign = 'right';
this._cont.appendChild(axis);
/* Draw labels and points */
w = 0;
items = new Array();
for (n = 0, i = this.ymax; (i > this.ymin) && (n < ygd - 1); i -= step, n++) {
item = document.createElement('span');
value = parseInt(i * multiplier) / multiplier;
item.appendChild(document.createTextNode(value));
axis.appendChild(item);
items.push([i, item]);
if (item.offsetWidth > w) { w = item.offsetWidth; }
}
/* Draw last label and point (lower left corner of chart) */
item = document.createElement('span');
item.appendChild(document.createTextNode(this.ymin));
axis.appendChild(item);
items.push([this.ymin, item]);
if (item.offsetWidth > w) { w = item.offsetWidth; }
/* Set width of container to width of widest label */
axis.style.width = w + 'px';
/* Recalculate chart width and position based on labels and legend */
this.chartx = w + 5;
this.charty = item.offsetHeight / 2;
this.charth = this.h - ((item.offsetHeight * 1.5) + 5);
this.chartw = this.w - (((this.legend)?this.legend.offsetWidth:0) + w + 10);
this.calc(this.chartw, this.charth, this.xlen, this.ymin, this.ymax, this.xgd, this.ygd);
/* Position labels on the axis */
n = this.range / this.charth;
yoffset = (this.ymin / n);
for (i = 0; i < items.length; i++) {
item = items[i][1];
pos = items[i][0];
if (pos == this.ymin) { y = this.charty + this.charth - 1; }
else { y = this.charty + (this.charth - (pos / n) + yoffset); }
this._painter.fillRect('black',this.chartx - 5, y, 5, 1);
ty = y - (item.offsetHeight/2);
item.style.position = 'absolute';
item.style.right = '0px';
item.style.top = ty + 'px';
}
};
Chart.prototype.drawHorizontalAxis = function(xlen, labels, xgd, precision) {
var axis, item, step, x, tx, n, multiplier;
/* Calculate offset, step size and rounding precision */
multiplier = Math.pow(10, precision);
n = this.chartw / (xgd - 1);
/* Create container */
axis = document.createElement('div');
axis.style.position = 'absolute';
axis.style.left = '0px';
axis.style.top = (this.charty + this.charth + 5) + 'px';
axis.style.width = this.w + 'px';
this._cont.appendChild(axis);
/* Draw labels and points */
for (i = 0; i < xgd; i++) {
item = document.createElement('span');
if (labels[i]) {
item.appendChild(document.createTextNode(labels[i]));
}
axis.appendChild(item);
x = this.chartx + (n * i);
tx = x - (item.offsetWidth/2);
item.style.position = 'absolute';
item.style.left = tx + 'px';
item.style.top = '0px';
this._painter.fillRect('black',x, this.charty + this.charth, 1, 5);
}
};
Chart.prototype.drawAxis = function() {
var x1, x2, y1, y2;
x1 = this.chartx;
x2 = this.chartx + this.chartw + 1;
y1 = this.charty;
y2 = this.charty + this.charth - 1;
this._painter.line('black',1,x1, y1, x1, y2);
this._painter.line('black',1,x1, y2, x2, y2);
};
Chart.prototype.drawBackground = function() {
this._painter.fillRect('white',0, 0, this.w, this.h);
};
Chart.prototype.drawGrid = function() {
if (this.xgrid) {
for (i = this.xgrid; i < this.chartw; i += this.xgrid) {
this._painter.line('silver',1,this.chartx + i, this.charty, this.chartx + i, this.charty + this.charth - 1);
}
}
if (this.ygrid) {
for (i = this.charth - this.ygrid; i > 0; i -= this.ygrid) {
this._painter.line('silver',1,this.chartx + 1, this.charty + i, this.chartx + this.chartw + 1, this.charty + i);
}
}
};
/*----------------------------------------------------------------------------\
| AbstractChartSeries |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
| Abstract class for common methods across all types of Charts |
\----------------------------------------------------------------------------*/
function AbstractChartSeries() {
}
AbstractChartSeries.prototype.getColor = function() {
return this.data['color'];
};
AbstractChartSeries.prototype.getLabel = function() {
return this.data['label'];
};
AbstractChartSeries.prototype.setRange = function(chart) {
if (this.data['values'].length > chart.xlen) { chart.xlen = this.data['values'].length; }
for (var j = 0; j < this.data['values'].length; j++) {
if ((this.data['values'][j] < chart.ymin) || (chart.ymin == null)) { chart.ymin = this.data['values'][j]; }
if (this.data['values'][j] > chart.ymax) { chart.ymax = this.data['values'][j]; }
}
};
AbstractChartSeries.prototype.getStackedValues = function(chart) {
var stacked=new Array();
if (this.data['stackedOn']) {
var stackedSeries=chart.findSeries(this.data['stackedOn']);
if (stackedSeries) {
stacked=stackedSeries.getStackedValues(chart);
}
}
for(var i=0;i chart.xlen) { len = chart.xlen; }
if (len) {
/* Determine position of each bar and draw it */
x = chart.chartx + this.offset + 1;
for (i = 0; i < len; i++) {
y = (values[i] / n);
barHt = (this.data['values'][i] / n);
painter.fillRect(this.data['color'],x,yBottom-y,this.data['width'],barHt);
x += chart.xstep;
}
}
};
/*----------------------------------------------------------------------------\
| AreaChartSeries |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
| Area Chart Series |
\----------------------------------------------------------------------------*/
function AreaChartSeries(data) {
// data hash contains keys
var defaultData = {
label:"AreaChart",// label - name of series
color:"#000", // color - HTML color for series
values:[], // values - array of values
};
for (var p in data) {defaultData[p]=data[p];}
this.data=defaultData;
this.base=AbstractChartSeries;
}
AreaChartSeries.prototype=new AbstractChartSeries;
AreaChartSeries.prototype.draw = function(chart) {
// draws a bar chart
var i, len, x, y, barHt, yBottom, n, yoffset,painter,values;
var points=[];
painter=chart.getPainter();
values=this.getStackedValues(chart);
if (values.length<=0) return;
/* Determine distance between points and offset */
n = chart.range / chart.charth;
yoffset = (chart.ymin / n);
yBottom = chart.charty + chart.charth + yoffset;
/* Begin line in lower left corner */
points.push({x:chart.chartx + 1,y:chart.charty + chart.charth - 1});
len = values.length;
if (len > chart.xlen) { len = chart.xlen; }
if (len) {
/* Determine position of each bar and draw it */
for (i = 0; i < len; i++) {
y = (values[i] / n);
barHt = (this.data['values'][i] / n);
points.push({x:chart.chartx + 1 + chart.xstep*i,y:yBottom-y});
}
/* Add end point at lower right corner */
points.push({x:chart.chartx + 1 + chart.xstep*(len-1),y:chart.charty + chart.charth - 1});
for (i = len-1; i >=0; i--) {
y = (values[i] / n);
barHt = (this.data['values'][i] / n);
points.push({x:chart.chartx + 1 + chart.xstep*i,y:yBottom-y+barHt});
}
painter.fillArea(this.data['color'],points);
}
};
/*----------------------------------------------------------------------------\
| LineChartSeries |
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -|
| Line Chart Series |
\----------------------------------------------------------------------------*/
function LineChartSeries(data) {
// data hash contains keys
var defaultData = {
label:"LineChart",// label - name of series
color:"#000", // color - HTML color for series
values:[], // values - array of values
};
for (var p in data) {defaultData[p]=data[p];}
this.data=defaultData;
this.base=AbstractChartSeries;
}
LineChartSeries.prototype=new AbstractChartSeries;
LineChartSeries.prototype.draw = function(chart) {
var i, len, x, y, n, yoffset;
painter=chart.getPainter();
values=this.getStackedValues(chart);
if (values.length<=0) return;
var points=[];
/* Determine distance between points and offset */
n = chart.range / chart.charth;
yoffset = (chart.ymin / n);
/* Add points */
for (i=0;i
|