1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2026-06-15 09:43:35 +00:00

Bowerize more components

- Move jquery-color into bower
- Move jquery-sparklines into bower
- Make swaks-tests/run-tests.sh discover its directory
- Update _base.html public resource includes to /public
This commit is contained in:
James Hillyerd
2016-02-26 21:57:15 -08:00
parent 5daa40b081
commit 5e15300d02
64 changed files with 106441 additions and 16 deletions
+6
View File
@@ -4,6 +4,12 @@
set -eo pipefail set -eo pipefail
# We need to be in swaks-tests directory
cmdpath="$(dirname "$0")"
if [ "$cmdpath" != "." ]; then
cd "$cmdpath"
fi
case "$1" in case "$1" in
"") "")
to="swaks" to="swaks"
+3 -1
View File
@@ -19,6 +19,8 @@
], ],
"dependencies": { "dependencies": {
"bootstrap": "3.3", "bootstrap": "3.3",
"jquery": "2" "jquery": "2",
"jquery-color": "^2.1.2",
"jquery-sparkline": "^2.1.3"
} }
} }
@@ -0,0 +1,15 @@
{
"name": "jquery-color",
"homepage": "https://github.com/jquery/jquery-color",
"version": "2.1.2",
"_release": "2.1.2",
"_resolution": {
"type": "version",
"tag": "2.1.2",
"commit": "9e5e04c1c4ee66427fbe04cfce8155b76748ca64"
},
"_source": "git://github.com/jquery/jquery-color.git",
"_target": "^2.1.2",
"_originalSource": "jquery-color",
"_direct": true
}
@@ -0,0 +1,4 @@
build/.sizecache.json
dist/
.DS_Store
node_modules
@@ -0,0 +1,3 @@
[submodule "test/qunit"]
path = test/qunit
url = git://github.com/jquery/qunit.git
@@ -0,0 +1,14 @@
{
"browser": true,
"curly": true,
"eqnull": true,
"eqeqeq": true,
"expr": true,
"jquery": true,
"noarg": true,
"onevar": true,
"quotmark": "double",
"trailing": true,
"undef": true,
"unused": true
}
@@ -0,0 +1,14 @@
Authors ordered by first contribution
John Resig <jeresig@gmail.com>
Scott González <scott.gonzalez@gmail.com>
Corey Frang <gnarf@gnarf.net>
eddiemonge <eddie@eddiemonge.com>
Krinkle <krinklemail@gmail.com>
Richard D. Worth <rdworth@gmail.com>
Jörn Zaefferer <joern.zaefferer@gmail.com>
Mike Sherov <mike.sherov@gmail.com>
Brendan Byrd <GitHub@ResonatorSoft.org>
Christoffer Sawicki <christoffer.sawicki@gmail.com>
Dmitry <df.creative@gmail.com>
Ben Olson <bseth99@yahoo.com>
@@ -0,0 +1,21 @@
Copyright 2013 jQuery Foundation and other contributors,
http://jquery.com
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.
@@ -0,0 +1,220 @@
# jQuery.Color()
Using jQuery Color in Production
--------------------------------
We release jQuery Color by itself, or in a bundle. The extended names can be inclided as a jQuery Color plugin, or you can download the version of jQuery Color that includes the names. Choose your build from the following list:
Current Version: 2.1.1
* jQuery Color [Compressed](http://code.jquery.com/color/jquery.color-2.1.1.min.js) [Uncompressed](http://code.jquery.com/color/jquery.color-2.1.1.js)
* jQuery Color Extended Names [Compressed](http://code.jquery.com/color/jquery.color.svg-names-2.1.1.min.js) [Uncompressed](http://code.jquery.com/color/jquery.color.svg-names-2.1.1.js)
* jQuery Color & Extended Names(previous two combined) [Compressed](http://code.jquery.com/color/jquery.color.plus-names-2.1.1.min.js) [Uncompressed](http://code.jquery.com/color/jquery.color.plus-names-2.1.1.js)
How to build and test jQuery Color
----------------------------------
First, get a copy of the git repo by running:
```shell
git clone git://github.com/jquery/jquery-color.git
```
Enter the directory and install the node dependencies:
```shell
cd jquery-color && npm install
```
Make sure you have `grunt` installed by testing:
```shell
grunt -version
```
If not, run:
```shell
npm install -g grunt
```
To run tests locally, run `grunt`, and this will run the tests in PhantomJS.
You can also run the tests in a browser by navigating to the `test/` directory, but first run `grunt` to install submodules.
## Animated colors
This plugins installs a [`cssHook`](http://api.jquery.com/jQuery.cssHooks/) which allows jQuery's [`.animate()`](http://api.jquery.com/animate) to animate between two colors.
Supported Properties
-------
`backgroundColor`, `borderBottomColor`, `borderLeftColor`, `borderRightColor`, `borderTopColor`, `color`, `columnRuleColor`, `outlineColor`, `textDecorationColor`, `textEmphasisColor`
Example Use
-------
```html
<!DOCTYPE html>
<html>
<head>
<style>
div {
background-color:#bada55;
width:100px;
border:1px solid green;
}
</style>
<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
<script src="jquery.color.min.js"></script>
</head>
<body>
<button id="go">Simple</button>
<button id="sat">Desaturate</button>
<div id="block">Hello!</div>
<script>
jQuery("#go").click(function(){
jQuery("#block").animate({
backgroundColor: "#abcdef"
}, 1500 );
});
jQuery("#sat").click(function(){
jQuery("#block").animate({
backgroundColor: jQuery.Color({ saturation: 0 })
}, 1500 );
});
</script>
</body>
</html>
```
## Supporting other properties
The `jQuery.Color.hook()` function can be called to support additional css properties as colors, and allow them to be animated.
Example Use
-----------
```javascript
// we want to animate SVG fill and stroke properties
jQuery.Color.hook( "fill stroke" );
```
## The jQuery.Color Factory
The `jQuery.Color()` function allows you to create and manipulate color objects that are accepted by jQuery's `.animate()` and `.css()` functions.
* Returns a new Color object, similar to `jQuery()` or `jQuery.Event`
* Accepts many formats to create a new Color object with a `jQuery.Color.fn` prototype
### Example uses:
```javascript
// Parsing String Colors:
jQuery.Color( "#abcdef" );
jQuery.Color( "rgb(100,200,255)" );
jQuery.Color( "rgba(100,200,255,0.5)" );
jQuery.Color( "aqua" );
// Creating Color Objects in Code:
// use null or undefined for values you wish to leave out
jQuery.Color( red, green, blue, alpha );
jQuery.Color([ red, green, blue, alpha ]);
jQuery.Color({ red: red, green: green, blue: blue, alpha: alpha });
jQuery.Color({ hue: hue, saturation: saturation, lightness: lightness, alpha: alpha });
// Helper to get value from CSS
jQuery.Color( element, cssProperty );
```
## jQuery.Color.fn / prototype / the Color Object methods
### Getters / Setters:
```javascript
red() // returns the "red" component of the color ( Integer from 0 - 255 )
red( val ) // returns a copy of the color object with the red set to val
green() // returns the "green" component of the color from ( Integer from 0 - 255 )
green( val ) // returns a copy of the color object with the green set to val
blue() // returns the "blue" component of the color from ( Integer from 0 - 255 )
blue( val ) // returns a copy of the color object with the blue set to val
alpha() // returns the "alpha" component of the color from ( Float from 0.0 - 1.0 )
alpha( val ) // returns a copy of the color object with the alpha set to val
hue() // returns the "hue" component of the color ( Integer from 0 - 359 )
hue( val ) // returns a copy of the color object with the hue set to val
saturation() // returns the "saturation" component of the color ( Float from 0.0 - 1.0 )
saturation( val ) // returns a copy of the color object with the saturation set to val
lightness() // returns the "lightness" component of the color ( Float from 0.0 - 1.0 )
lightness( val ) // returns a copy of the color object with the lightness set to val
// all of the above values can also take strings in the format of "+=100" or "-=100"
rgba() // returns a rgba "tuple" [ red, green, blue, alpha ]
// rgba() setters: returns a copy of the color with any defined values set to the new value
rgba( red, green, blue, alpha )
rgba({ red: red, green: green, blue: blue, alpha: alpha })
rgba([ red, green, blue, alpha ])
hsla() // returns a HSL tuple [ hue, saturation, lightness, alpha ]
// much like the rgb setter - returns a copy with any defined values set
hsla( hue, saturation, lightness, alpha )
hsla({ hue: hue, saturation: saturation, lightness: lightness, alpha: alpha )
hsla([ hue, saturation, lightness, alpha ])
```
### String Methods:
```javascript
toRgbaString() // returns a css string "rgba(255, 255, 255, 0.4)"
toHslaString() // returns a css string "hsla(330, 75%, 25%, 0.4)"
toHexString( includeAlpha ) // returns a css string "#abcdef", with "includeAlpha" uses "#rrggbbaa" (alpha *= 255)
```
The `toRgbaString` and `toHslaString` methods will only include the alpha channel if it is not `1`. They will return `rgb(...)` and `hsl(...)` strings if the alpha is set to `1`.
### Working with other colors:
```javascript
transition( othercolor, distance ) // the color distance ( 0.0 - 1.0 ) of the way between this color and othercolor
blend( othercolor ) // Will apply this color on top of the other color using alpha blending
is( othercolor ) // Will determine if this color is equal to all defined properties of othercolor
```
## jQuery.Color properties
## Internals on The Color Object
* Internally, RGBA values are stored as `color._rgba[0] = red, color._rgba[1] = green, color._rgba[2] = blue, color._rgba[3] = alpha`. However, please remember there are nice convenient setters and getters for each of these properties.
* `undefined`/`null` values for colors indicate non-existence. This signals the `transition()` function to keep whatever value was set in the other end of the transition. For example, animating to `jQuery.Color([ 255, null, null, 1 ])` would only animate the red and alpha values of the color.
###`jQuery.Color.names`
A list of named colors is stored on the `jQuery.Color.names` object. The value they contain should be parseable by `jQuery.Color()`. All names on this object should be lowercased. I.E. `jQuery.Color("Red")` is the same as doing `jQuery.Color( jQuery.Color.names["red"] );`
There is also a named color `"_default"` which by default is white, this is used for situations where a color is unparseable.
###`"transparent"`
A special note about the color `"transparent"` - It returns `null` for red green and blue unless you specify colors for these values.
```javascript
jQuery.Color("#abcdef").transition("transparent", 0.5)
```
Animating to or from the value `"transparent"` will still use "#abcdef" for red green and blue.
##HSLA Support
If a color is created using any of the HSLA functions or parsers, it will keep the `_rgba` array up to date as well as having a `_hsla` array. Once an RGBA operation is performed on HSLA, however, the `_hsla` cache is removed and all operations will continue based off of rgb (unless you go back into HSLA). The `._hsla` array follows the same format as `._rbga`, `[hue, saturation, lightness, alpha ]`. If you need to build an HSLA color from an HSLA array, `jQuery.Color().hsla( array )` works for that purpose.
**Colors with 0 saturation, or 100%/0% lightness will be stored with a hue of 0**
##Extensibility
It is possible for you to add your own functions to the color object. For instance, this function will tell you if its better to use black or white on a given background color.
```javascript
// method taken from https://gist.github.com/960189
jQuery.Color.fn.contrastColor = function() {
var r = this._rgba[0], g = this._rgba[1], b = this._rgba[2];
return (((r*299)+(g*587)+(b*144))/1000) >= 131.5 ? "black" : "white";
};
// usage examples:
jQuery.Color("#bada55").contrastColor(); // "black"
element.css( "color", jQuery.Color( element, "backgroundColor" ).contrastColor() );
```
@@ -0,0 +1,34 @@
{
"name": "color",
"title": "jQuery Color",
"description": "jQuery plugin for color manipulation and animation support.",
"keywords": [
"color",
"animation"
],
"version": "2.1.2",
"author": {
"name": "jQuery Foundation and other contributors",
"url": "https://github.com/jquery/jquery-color/blob/2.1.2/AUTHORS.txt"
},
"maintainers": [
{
"name": "Corey Frang",
"email": "gnarf37@gmail.com",
"url": "http://gnarf.net"
}
],
"licenses": [
{
"type": "MIT",
"url": "https://github.com/jquery/jquery-color/blob/2.1.2/MIT-LICENSE.txt"
}
],
"bugs": "https://github.com/jquery/jquery-color/issues",
"homepage": "https://github.com/jquery/jquery-color",
"docs": "https://github.com/jquery/jquery-color",
"download": "http://code.jquery.com/#color",
"dependencies": {
"jquery": ">=1.5"
}
}
@@ -0,0 +1,187 @@
/*jshint node: true */
module.exports = function( grunt ) {
"use strict";
var max = [ "dist/jquery.color.js", "dist/jquery.color.svg-names.js" ],
min = [ "dist/jquery.color.min.js", "dist/jquery.color.svg-names.min.js", "dist/jquery.color.plus-names.min.js"],
combined = "dist/jquery.color.plus-names.js",
minify = {},
concat = {};
minify[ min[0] ] = [ "<banner>", max[0] ];
minify[ min[1] ] = [ "<banner:meta.bannerSvg>", max[1] ];
minify[ min[2] ] = [ "<banner:meta.bannerCombined>", combined ];
concat[ combined ] = [ max[0], max[1] ];
grunt.loadNpmTasks( "grunt-compare-size" );
grunt.loadNpmTasks( "grunt-git-authors" );
grunt.initConfig({
pkg: "<json:package.json>",
meta: {
banner: "/*! jQuery Color v@<%= pkg.version %> http://github.com/jquery/jquery-color | jquery.org/license */",
bannerSvg: "/*! jQuery Color v@<%= pkg.version %> SVG Color Names http://github.com/jquery/jquery-color | jquery.org/license */",
bannerCombined: "/*! jQuery Color v@<%= pkg.version %> with SVG Color Names http://github.com/jquery/jquery-color | jquery.org/license */"
},
lint: {
src: [ "jquery.color.js", "jquery.color.svg-names.js" ],
grunt: "grunt.js",
test: "test/unit/**"
},
jshint: (function() {
function parserc( path ) {
var rc = grunt.file.readJSON( (path || "") + ".jshintrc" ),
settings = {
options: rc,
globals: rc.globals || {}
};
(rc.predef || []).forEach(function( prop ) {
settings.globals[ prop ] = true;
});
delete rc.predef;
return settings;
}
return {
src: parserc(),
grunt: parserc(),
test: parserc( "test/unit/" )
};
})(),
qunit: {
files: "test/index.html"
},
concat: concat,
min: minify,
watch: {
files: [ "<config:lint.src>", "<config:lint.test>", "<config:lint.grunt>" ],
tasks: "default"
},
compare_size: {
"color": [ max[0], min[0] ],
"svg-names": [ max[1], min[1] ],
"combined": [ combined, min[2] ]
}
});
grunt.registerHelper( "git-date", function( fn ) {
grunt.utils.spawn({
cmd: "git",
args: [ "log", "-1", "--pretty=format:%ad" ]
}, function( error, result ) {
if ( error ) {
grunt.log.error( error );
return fn( error );
}
fn( null, result );
});
});
grunt.registerTask( "submodules", function() {
var done = this.async();
grunt.verbose.write( "Updating submodules..." );
grunt.utils.spawn({
cmd: "git",
args: [ "submodule", "update", "--init" ]
}, function( err, result ) {
if ( err ) {
grunt.verbose.error();
done( err );
return;
}
grunt.log.writeln( result );
done();
});
});
grunt.registerTask( "max", function() {
var done = this.async(),
version = grunt.config( "pkg.version" );
if ( process.env.COMMIT ) {
version += " " + process.env.COMMIT;
}
grunt.helper( "git-date", function( error, date ) {
if ( error ) {
return done( false );
}
max.forEach( function( dist ) {
grunt.file.copy( dist.replace( "dist/", "" ), dist, {
process: function( source ) {
return source
.replace( /@VERSION/g, version )
.replace( /@DATE/g, date );
}
});
});
done();
});
});
grunt.registerTask( "testswarm", function( commit, configFile ) {
var testswarm = require( "testswarm" ),
config = grunt.file.readJSON( configFile ).jquerycolor;
config.jobName = "jQuery Color commit #<a href='https://github.com/jquery/jquery-color/commit/" + commit + "'>" + commit.substr( 0, 10 ) + "</a>";
config["runNames[]"] = "jQuery color";
config["runUrls[]"] = config.testUrl + commit + "/test/index.html";
config["browserSets[]"] = ["popular"];
testswarm({
url: config.swarmUrl,
pollInterval: 10000,
timeout: 1000 * 60 * 30,
done: this.async()
}, config);
});
grunt.registerTask( "manifest", function() {
var pkg = grunt.config( "pkg" );
grunt.file.write( "color.jquery.json", JSON.stringify({
name: "color",
title: pkg.title,
description: pkg.description,
keywords: pkg.keywords,
version: pkg.version,
author: {
name: pkg.author.name,
url: pkg.author.url.replace( "master", pkg.version )
},
maintainers: pkg.maintainers,
licenses: pkg.licenses.map(function( license ) {
license.url = license.url.replace( "master", pkg.version );
return license;
}),
bugs: pkg.bugs,
homepage: pkg.homepage,
docs: pkg.homepage,
download: "http://code.jquery.com/#color",
dependencies: {
jquery: ">=1.5"
}
}, null, "\t" ) );
});
grunt.registerTask( "default", "lint submodules qunit build compare_size" );
grunt.registerTask( "build", "max concat min" );
};
@@ -0,0 +1,663 @@
/*!
* jQuery Color Animations v@VERSION
* https://github.com/jquery/jquery-color
*
* Copyright 2013 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* Date: @DATE
*/
(function( jQuery, undefined ) {
var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
// plusequals test for += 100 -= 100
rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
// a set of RE's that can match strings and generate color tuples.
stringParsers = [{
re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
execResult[ 1 ],
execResult[ 2 ],
execResult[ 3 ],
execResult[ 4 ]
];
}
}, {
re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
execResult[ 1 ] * 2.55,
execResult[ 2 ] * 2.55,
execResult[ 3 ] * 2.55,
execResult[ 4 ]
];
}
}, {
// this regex ignores A-F because it's compared against an already lowercased string
re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
parse: function( execResult ) {
return [
parseInt( execResult[ 1 ], 16 ),
parseInt( execResult[ 2 ], 16 ),
parseInt( execResult[ 3 ], 16 )
];
}
}, {
// this regex ignores A-F because it's compared against an already lowercased string
re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
parse: function( execResult ) {
return [
parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
];
}
}, {
re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
space: "hsla",
parse: function( execResult ) {
return [
execResult[ 1 ],
execResult[ 2 ] / 100,
execResult[ 3 ] / 100,
execResult[ 4 ]
];
}
}],
// jQuery.Color( )
color = jQuery.Color = function( color, green, blue, alpha ) {
return new jQuery.Color.fn.parse( color, green, blue, alpha );
},
spaces = {
rgba: {
props: {
red: {
idx: 0,
type: "byte"
},
green: {
idx: 1,
type: "byte"
},
blue: {
idx: 2,
type: "byte"
}
}
},
hsla: {
props: {
hue: {
idx: 0,
type: "degrees"
},
saturation: {
idx: 1,
type: "percent"
},
lightness: {
idx: 2,
type: "percent"
}
}
}
},
propTypes = {
"byte": {
floor: true,
max: 255
},
"percent": {
max: 1
},
"degrees": {
mod: 360,
floor: true
}
},
support = color.support = {},
// element for support tests
supportElem = jQuery( "<p>" )[ 0 ],
// colors = jQuery.Color.names
colors,
// local aliases of functions called often
each = jQuery.each;
// determine rgba support immediately
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
// define cache name and alpha properties
// for rgba and hsla spaces
each( spaces, function( spaceName, space ) {
space.cache = "_" + spaceName;
space.props.alpha = {
idx: 3,
type: "percent",
def: 1
};
});
function clamp( value, prop, allowEmpty ) {
var type = propTypes[ prop.type ] || {};
if ( value == null ) {
return (allowEmpty || !prop.def) ? null : prop.def;
}
// ~~ is an short way of doing floor for positive numbers
value = type.floor ? ~~value : parseFloat( value );
// IE will pass in empty strings as value for alpha,
// which will hit this case
if ( isNaN( value ) ) {
return prop.def;
}
if ( type.mod ) {
// we add mod before modding to make sure that negatives values
// get converted properly: -10 -> 350
return (value + type.mod) % type.mod;
}
// for now all property types without mod have min and max
return 0 > value ? 0 : type.max < value ? type.max : value;
}
function stringParse( string ) {
var inst = color(),
rgba = inst._rgba = [];
string = string.toLowerCase();
each( stringParsers, function( i, parser ) {
var parsed,
match = parser.re.exec( string ),
values = match && parser.parse( match ),
spaceName = parser.space || "rgba";
if ( values ) {
parsed = inst[ spaceName ]( values );
// if this was an rgba parse the assignment might happen twice
// oh well....
inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
rgba = inst._rgba = parsed._rgba;
// exit each( stringParsers ) here because we matched
return false;
}
});
// Found a stringParser that handled it
if ( rgba.length ) {
// if this came from a parsed string, force "transparent" when alpha is 0
// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
if ( rgba.join() === "0,0,0,0" ) {
jQuery.extend( rgba, colors.transparent );
}
return inst;
}
// named colors
return colors[ string ];
}
color.fn = jQuery.extend( color.prototype, {
parse: function( red, green, blue, alpha ) {
if ( red === undefined ) {
this._rgba = [ null, null, null, null ];
return this;
}
if ( red.jquery || red.nodeType ) {
red = jQuery( red ).css( green );
green = undefined;
}
var inst = this,
type = jQuery.type( red ),
rgba = this._rgba = [];
// more than 1 argument specified - assume ( red, green, blue, alpha )
if ( green !== undefined ) {
red = [ red, green, blue, alpha ];
type = "array";
}
if ( type === "string" ) {
return this.parse( stringParse( red ) || colors._default );
}
if ( type === "array" ) {
each( spaces.rgba.props, function( key, prop ) {
rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
});
return this;
}
if ( type === "object" ) {
if ( red instanceof color ) {
each( spaces, function( spaceName, space ) {
if ( red[ space.cache ] ) {
inst[ space.cache ] = red[ space.cache ].slice();
}
});
} else {
each( spaces, function( spaceName, space ) {
var cache = space.cache;
each( space.props, function( key, prop ) {
// if the cache doesn't exist, and we know how to convert
if ( !inst[ cache ] && space.to ) {
// if the value was null, we don't need to copy it
// if the key was alpha, we don't need to copy it either
if ( key === "alpha" || red[ key ] == null ) {
return;
}
inst[ cache ] = space.to( inst._rgba );
}
// this is the only case where we allow nulls for ALL properties.
// call clamp with alwaysAllowEmpty
inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
});
// everything defined but alpha?
if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
// use the default of 1
inst[ cache ][ 3 ] = 1;
if ( space.from ) {
inst._rgba = space.from( inst[ cache ] );
}
}
});
}
return this;
}
},
is: function( compare ) {
var is = color( compare ),
same = true,
inst = this;
each( spaces, function( _, space ) {
var localCache,
isCache = is[ space.cache ];
if (isCache) {
localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
each( space.props, function( _, prop ) {
if ( isCache[ prop.idx ] != null ) {
same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
return same;
}
});
}
return same;
});
return same;
},
_space: function() {
var used = [],
inst = this;
each( spaces, function( spaceName, space ) {
if ( inst[ space.cache ] ) {
used.push( spaceName );
}
});
return used.pop();
},
transition: function( other, distance ) {
var end = color( other ),
spaceName = end._space(),
space = spaces[ spaceName ],
startColor = this.alpha() === 0 ? color( "transparent" ) : this,
start = startColor[ space.cache ] || space.to( startColor._rgba ),
result = start.slice();
end = end[ space.cache ];
each( space.props, function( key, prop ) {
var index = prop.idx,
startValue = start[ index ],
endValue = end[ index ],
type = propTypes[ prop.type ] || {};
// if null, don't override start value
if ( endValue === null ) {
return;
}
// if null - use end
if ( startValue === null ) {
result[ index ] = endValue;
} else {
if ( type.mod ) {
if ( endValue - startValue > type.mod / 2 ) {
startValue += type.mod;
} else if ( startValue - endValue > type.mod / 2 ) {
startValue -= type.mod;
}
}
result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
}
});
return this[ spaceName ]( result );
},
blend: function( opaque ) {
// if we are already opaque - return ourself
if ( this._rgba[ 3 ] === 1 ) {
return this;
}
var rgb = this._rgba.slice(),
a = rgb.pop(),
blend = color( opaque )._rgba;
return color( jQuery.map( rgb, function( v, i ) {
return ( 1 - a ) * blend[ i ] + a * v;
}));
},
toRgbaString: function() {
var prefix = "rgba(",
rgba = jQuery.map( this._rgba, function( v, i ) {
return v == null ? ( i > 2 ? 1 : 0 ) : v;
});
if ( rgba[ 3 ] === 1 ) {
rgba.pop();
prefix = "rgb(";
}
return prefix + rgba.join() + ")";
},
toHslaString: function() {
var prefix = "hsla(",
hsla = jQuery.map( this.hsla(), function( v, i ) {
if ( v == null ) {
v = i > 2 ? 1 : 0;
}
// catch 1 and 2
if ( i && i < 3 ) {
v = Math.round( v * 100 ) + "%";
}
return v;
});
if ( hsla[ 3 ] === 1 ) {
hsla.pop();
prefix = "hsl(";
}
return prefix + hsla.join() + ")";
},
toHexString: function( includeAlpha ) {
var rgba = this._rgba.slice(),
alpha = rgba.pop();
if ( includeAlpha ) {
rgba.push( ~~( alpha * 255 ) );
}
return "#" + jQuery.map( rgba, function( v ) {
// default to 0 when nulls exist
v = ( v || 0 ).toString( 16 );
return v.length === 1 ? "0" + v : v;
}).join("");
},
toString: function() {
return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
}
});
color.fn.parse.prototype = color.fn;
// hsla conversions adapted from:
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
function hue2rgb( p, q, h ) {
h = ( h + 1 ) % 1;
if ( h * 6 < 1 ) {
return p + (q - p) * h * 6;
}
if ( h * 2 < 1) {
return q;
}
if ( h * 3 < 2 ) {
return p + (q - p) * ((2/3) - h) * 6;
}
return p;
}
spaces.hsla.to = function ( rgba ) {
if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
return [ null, null, null, rgba[ 3 ] ];
}
var r = rgba[ 0 ] / 255,
g = rgba[ 1 ] / 255,
b = rgba[ 2 ] / 255,
a = rgba[ 3 ],
max = Math.max( r, g, b ),
min = Math.min( r, g, b ),
diff = max - min,
add = max + min,
l = add * 0.5,
h, s;
if ( min === max ) {
h = 0;
} else if ( r === max ) {
h = ( 60 * ( g - b ) / diff ) + 360;
} else if ( g === max ) {
h = ( 60 * ( b - r ) / diff ) + 120;
} else {
h = ( 60 * ( r - g ) / diff ) + 240;
}
// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
if ( diff === 0 ) {
s = 0;
} else if ( l <= 0.5 ) {
s = diff / add;
} else {
s = diff / ( 2 - add );
}
return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
};
spaces.hsla.from = function ( hsla ) {
if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
return [ null, null, null, hsla[ 3 ] ];
}
var h = hsla[ 0 ] / 360,
s = hsla[ 1 ],
l = hsla[ 2 ],
a = hsla[ 3 ],
q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
p = 2 * l - q;
return [
Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
Math.round( hue2rgb( p, q, h ) * 255 ),
Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
a
];
};
each( spaces, function( spaceName, space ) {
var props = space.props,
cache = space.cache,
to = space.to,
from = space.from;
// makes rgba() and hsla()
color.fn[ spaceName ] = function( value ) {
// generate a cache for this space if it doesn't exist
if ( to && !this[ cache ] ) {
this[ cache ] = to( this._rgba );
}
if ( value === undefined ) {
return this[ cache ].slice();
}
var ret,
type = jQuery.type( value ),
arr = ( type === "array" || type === "object" ) ? value : arguments,
local = this[ cache ].slice();
each( props, function( key, prop ) {
var val = arr[ type === "object" ? key : prop.idx ];
if ( val == null ) {
val = local[ prop.idx ];
}
local[ prop.idx ] = clamp( val, prop );
});
if ( from ) {
ret = color( from( local ) );
ret[ cache ] = local;
return ret;
} else {
return color( local );
}
};
// makes red() green() blue() alpha() hue() saturation() lightness()
each( props, function( key, prop ) {
// alpha is included in more than one space
if ( color.fn[ key ] ) {
return;
}
color.fn[ key ] = function( value ) {
var vtype = jQuery.type( value ),
fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
local = this[ fn ](),
cur = local[ prop.idx ],
match;
if ( vtype === "undefined" ) {
return cur;
}
if ( vtype === "function" ) {
value = value.call( this, cur );
vtype = jQuery.type( value );
}
if ( value == null && prop.empty ) {
return this;
}
if ( vtype === "string" ) {
match = rplusequals.exec( value );
if ( match ) {
value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
}
}
local[ prop.idx ] = value;
return this[ fn ]( local );
};
});
});
// add cssHook and .fx.step function for each named hook.
// accept a space separated string of properties
color.hook = function( hook ) {
var hooks = hook.split( " " );
each( hooks, function( i, hook ) {
jQuery.cssHooks[ hook ] = {
set: function( elem, value ) {
var parsed, curElem,
backgroundColor = "";
if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
value = color( parsed || value );
if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
curElem = hook === "backgroundColor" ? elem.parentNode : elem;
while (
(backgroundColor === "" || backgroundColor === "transparent") &&
curElem && curElem.style
) {
try {
backgroundColor = jQuery.css( curElem, "backgroundColor" );
curElem = curElem.parentNode;
} catch ( e ) {
}
}
value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
backgroundColor :
"_default" );
}
value = value.toRgbaString();
}
try {
elem.style[ hook ] = value;
} catch( e ) {
// wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
}
}
};
jQuery.fx.step[ hook ] = function( fx ) {
if ( !fx.colorInit ) {
fx.start = color( fx.elem, hook );
fx.end = color( fx.end );
fx.colorInit = true;
}
jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
};
});
};
color.hook( stepHooks );
jQuery.cssHooks.borderColor = {
expand: function( value ) {
var expanded = {};
each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
expanded[ "border" + part + "Color" ] = value;
});
return expanded;
}
};
// Basic color names only.
// Usage of any of the other color names requires adding yourself or including
// jquery.color.svg-names.js.
colors = jQuery.Color.names = {
// 4.1. Basic color keywords
aqua: "#00ffff",
black: "#000000",
blue: "#0000ff",
fuchsia: "#ff00ff",
gray: "#808080",
green: "#008000",
lime: "#00ff00",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
purple: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
teal: "#008080",
white: "#ffffff",
yellow: "#ffff00",
// 4.2.3. "transparent" color keyword
transparent: [ null, null, null, 0 ],
_default: "#ffffff"
};
})( jQuery );
@@ -0,0 +1,146 @@
/*!
* jQuery Color Animations v@VERSION - SVG Color Names
* https://github.com/jquery/jquery-color
*
* Remaining HTML/CSS color names per W3C's CSS Color Module Level 3.
* http://www.w3.org/TR/css3-color/#svg-color
*
* Copyright 2013 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* Date: @DATE
*/
jQuery.extend( jQuery.Color.names, {
// 4.3. Extended color keywords (minus the basic ones in core color plugin)
aliceblue: "#f0f8ff",
antiquewhite: "#faebd7",
aquamarine: "#7fffd4",
azure: "#f0ffff",
beige: "#f5f5dc",
bisque: "#ffe4c4",
blanchedalmond: "#ffebcd",
blueviolet: "#8a2be2",
brown: "#a52a2a",
burlywood: "#deb887",
cadetblue: "#5f9ea0",
chartreuse: "#7fff00",
chocolate: "#d2691e",
coral: "#ff7f50",
cornflowerblue: "#6495ed",
cornsilk: "#fff8dc",
crimson: "#dc143c",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgoldenrod: "#b8860b",
darkgray: "#a9a9a9",
darkgreen: "#006400",
darkgrey: "#a9a9a9",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkseagreen: "#8fbc8f",
darkslateblue: "#483d8b",
darkslategray: "#2f4f4f",
darkslategrey: "#2f4f4f",
darkturquoise: "#00ced1",
darkviolet: "#9400d3",
deeppink: "#ff1493",
deepskyblue: "#00bfff",
dimgray: "#696969",
dimgrey: "#696969",
dodgerblue: "#1e90ff",
firebrick: "#b22222",
floralwhite: "#fffaf0",
forestgreen: "#228b22",
gainsboro: "#dcdcdc",
ghostwhite: "#f8f8ff",
gold: "#ffd700",
goldenrod: "#daa520",
greenyellow: "#adff2f",
grey: "#808080",
honeydew: "#f0fff0",
hotpink: "#ff69b4",
indianred: "#cd5c5c",
indigo: "#4b0082",
ivory: "#fffff0",
khaki: "#f0e68c",
lavender: "#e6e6fa",
lavenderblush: "#fff0f5",
lawngreen: "#7cfc00",
lemonchiffon: "#fffacd",
lightblue: "#add8e6",
lightcoral: "#f08080",
lightcyan: "#e0ffff",
lightgoldenrodyellow: "#fafad2",
lightgray: "#d3d3d3",
lightgreen: "#90ee90",
lightgrey: "#d3d3d3",
lightpink: "#ffb6c1",
lightsalmon: "#ffa07a",
lightseagreen: "#20b2aa",
lightskyblue: "#87cefa",
lightslategray: "#778899",
lightslategrey: "#778899",
lightsteelblue: "#b0c4de",
lightyellow: "#ffffe0",
limegreen: "#32cd32",
linen: "#faf0e6",
mediumaquamarine: "#66cdaa",
mediumblue: "#0000cd",
mediumorchid: "#ba55d3",
mediumpurple: "#9370db",
mediumseagreen: "#3cb371",
mediumslateblue: "#7b68ee",
mediumspringgreen: "#00fa9a",
mediumturquoise: "#48d1cc",
mediumvioletred: "#c71585",
midnightblue: "#191970",
mintcream: "#f5fffa",
mistyrose: "#ffe4e1",
moccasin: "#ffe4b5",
navajowhite: "#ffdead",
oldlace: "#fdf5e6",
olivedrab: "#6b8e23",
orange: "#ffa500",
orangered: "#ff4500",
orchid: "#da70d6",
palegoldenrod: "#eee8aa",
palegreen: "#98fb98",
paleturquoise: "#afeeee",
palevioletred: "#db7093",
papayawhip: "#ffefd5",
peachpuff: "#ffdab9",
peru: "#cd853f",
pink: "#ffc0cb",
plum: "#dda0dd",
powderblue: "#b0e0e6",
rosybrown: "#bc8f8f",
royalblue: "#4169e1",
saddlebrown: "#8b4513",
salmon: "#fa8072",
sandybrown: "#f4a460",
seagreen: "#2e8b57",
seashell: "#fff5ee",
sienna: "#a0522d",
skyblue: "#87ceeb",
slateblue: "#6a5acd",
slategray: "#708090",
slategrey: "#708090",
snow: "#fffafa",
springgreen: "#00ff7f",
steelblue: "#4682b4",
tan: "#d2b48c",
thistle: "#d8bfd8",
tomato: "#ff6347",
turquoise: "#40e0d0",
violet: "#ee82ee",
wheat: "#f5deb3",
whitesmoke: "#f5f5f5",
yellowgreen: "#9acd32"
});
@@ -0,0 +1,37 @@
{
"name": "jquery-color",
"title": "jQuery Color",
"description": "jQuery plugin for color manipulation and animation support.",
"version": "2.1.2",
"homepage": "https://github.com/jquery/jquery-color",
"author": {
"name": "jQuery Foundation and other contributors",
"url": "https://github.com/jquery/jquery-color/blob/master/AUTHORS.txt"
},
"maintainers": [
{
"name": "Corey Frang",
"email": "gnarf37@gmail.com",
"url": "http://gnarf.net"
}
],
"repository": {
"type": "git",
"url": "git://github.com/jquery/jquery-color.git"
},
"bugs": "https://github.com/jquery/jquery-color/issues",
"licenses": [
{
"type": "MIT",
"url": "https://github.com/jquery/jquery-color/blob/master/MIT-LICENSE.txt"
}
],
"dependencies": {},
"devDependencies": {
"grunt": "~0.3.17",
"grunt-compare-size": ">=0.1.4",
"grunt-git-authors": "1.0.0",
"testswarm": "0.2.2"
},
"keywords": [ "color", "animation" ]
}
@@ -0,0 +1,9 @@
// load testswarm agent
(function() {
var url = window.location.search;
url = decodeURIComponent( url.slice( url.indexOf("swarmURL=") + 9 ) );
if ( !url || url.indexOf("http") !== 0 ) {
return;
}
document.write("<scr" + "ipt src='http://swarm.jquery.org/js/inject.js?" + (new Date).getTime() + "'></scr" + "ipt>");
})();
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>jQuery-Color Test Suite</title>
<link rel="Stylesheet" media="screen" href="qunit/qunit/qunit.css" />
<script src="data/testinit.js"></script>
<script src="jquery.js"></script>
<script src="../jquery.color.js"></script>
<script src="qunit/qunit/qunit.js"></script>
<script src="unit/color.js"></script>
<script src="data/swarminject.js"></script>
</head>
<body id="body">
<h1 id="qunit-header">jQuery-Color Test Suite</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
(function() {
var parts = document.location.search.slice( 1 ).split( "&" ),
length = parts.length,
i = 0,
current,
version,
url;
for ( ; i < length; i++ ) {
current = parts[ i ].split( "=" );
if ( current[ 0 ] === "jquery" ) {
version = current[ 1 ];
break;
}
}
if ( version === "git" ) {
url = "http://code.jquery.com/jquery-git.js";
} else {
url = "jquery-" + ( version || "1.7.2" ) + ".js";
}
document.write( "<script src='" + url + "'></script>" );
}() );
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="jquery-1.5.1.js"></script>
<script type="text/javascript" src="../jquery.color.js"></script>
</head>
<body>
<div id="test" style="background-color: #00ffff">Test string</div>
<script type="text/javascript">
//<![CDATA[
var $div = $("#test");
$div./*animate({"background-color": "#ffff00"}, 300).*/
animate({"background-color": 'transparent'}, 400);
// var savedColor = $div.css("backgroundColor");
// alert(savedColor);
// $div.animate({"background-color": "#ffff00"}, 300).
// animate({"background-color": savedColor}, 400);
//]]>
</script>
</body>
</html>
@@ -0,0 +1,29 @@
{
"boss": true,
"browser": true,
"curly": true,
"eqnull": true,
"eqeqeq": true,
"expr": true,
"jquery": true,
"latedef": true,
"noarg": true,
"onevar": true,
"quotmark": "double",
"trailing": true,
"undef": true,
"unused": true,
"predef": [
"asyncTest",
"deepEqual",
"equal",
"expect",
"module",
"notEqual",
"ok",
"start",
"stop",
"strictEqual",
"test"
]
}
@@ -0,0 +1,647 @@
module( "parse" );
function testParts( color, parts ) {
var prefix = parts.prefix || "";
if ( parts.expect ) {
expect( parts.expect );
}
jQuery.each( parts, function( key , value ) {
// these two properties are just helpers for the test function, ignore them
if ( key === "expect" || key === "prefix" ) {
return;
}
strictEqual( color[ key ](), value, prefix + "."+key+"() is "+value);
});
}
function parseTest( str, results, descr ) {
test( descr || "jQuery.Color( \""+str+"\" )", function() {
var color = descr ? str : jQuery.Color( str );
testParts( color, results );
});
}
test( "jQuery.Color( 255, 255, 255 )", function() {
expect( 4 );
testParts( jQuery.Color( 255, 255, 255 ), {
expect: 4,
red: 255,
green: 255,
blue: 255,
alpha: 1
});
});
test( "jQuery.Color( element, \"color\" )", function() {
var $div = jQuery( "<div>" ).appendTo( "body" ).css( "color", "#fff" );
expect( 8 );
testParts( jQuery.Color( $div, "color" ), {
prefix: "jQuery(<div>): ",
red: 255,
green: 255,
blue: 255,
alpha: 1
});
testParts( jQuery.Color( $div[ 0 ], "color" ), {
prefix: "<div>: ",
red: 255,
green: 255,
blue: 255,
alpha: 1
});
$div.remove();
});
parseTest( jQuery.Color({ red: 100 }), {
expect: 4,
red: 100,
green: null,
blue: null,
alpha: null
}, "jQuery.Color({ red: 100 })" );
test( "jQuery.Color({ blue: 100 })", function() {
var blue = jQuery.Color({ blue: 100 });
testParts( blue, {
red: null,
green: null,
blue: 100,
alpha: null
});
ok( !blue._hsla, "No HSLA cache");
});
test( "jQuery.Color({ alpha: 1 })", function() {
var blue = jQuery.Color({ alpha: 1 });
testParts( blue, {
red: null,
green: null,
blue: null,
alpha: 1
});
ok( !blue._hsla, "No HSLA cache");
});
test( "jQuery.Color({ alpha: 1, hue: 100 })", function() {
var blue = jQuery.Color({ alpha: 1, hue: 100 });
testParts( blue, {
red: null,
green: null,
blue: null,
alpha: 1,
hue: 100,
saturation: null,
lightness: null
});
deepEqual( blue._hsla, [ 100, null, null, 1 ], "HSLA cache has correct values");
});
test( "jQuery.Color({ hue: 100, saturation: 1, lightness: 0.5 })", function() {
var blue = jQuery.Color({ hue: 100, saturation: 1, lightness: 0.5 });
testParts( blue, {
red: 85,
green: 255,
blue: 0,
alpha: 1,
hue: 100,
saturation: 1,
lightness: 0.5
});
deepEqual( blue._rgba, [ 85, 255, 0, 1 ], "RGBA cache has correct values");
deepEqual( blue._hsla, [ 100, 1, 0.5, 1 ], "HSLA cache has correct values");
});
parseTest( jQuery.Color( jQuery.Color( "red" ) ), {
expect: 4,
red: 255,
green: 0,
blue: 0,
alpha: 1
}, "jQuery.Color( jQuery.Color(\"red\") )" );
parseTest( jQuery.Color([ 255, 255, 255 ]), {
expect: 4,
red: 255,
green: 255,
blue: 255,
alpha: 1
}, "jQuery.Color([ 255, 255, 255 ])" );
parseTest( "", {
expect: 4,
red: 255,
green: 255,
blue: 255,
alpha: 1
});
var sevens = {
expect: 4,
red: 119,
green: 119,
blue: 119,
alpha: 1
};
parseTest( "#777", sevens );
parseTest( "#777777", sevens );
var fiftypercent = {
expect: 4,
red: 127,
green: 127,
blue: 127,
alpha: 1
}, fiftypercentalpha = {
expect: 4,
red: 127,
green: 127,
blue: 127,
alpha: 0.5
};
parseTest( "rgb(127,127,127)", fiftypercent );
parseTest( "rgb(50%,50%,50%)", fiftypercent );
parseTest( "rgba(127,127,127,1)", fiftypercent );
parseTest( "rgba(50%,50%,50%,1)", fiftypercent );
parseTest( "rgba(127,127,127,0.5)", fiftypercentalpha );
parseTest( "rgba(50%,50%,50%,0.5)", fiftypercentalpha );
parseTest( "rgba(127, 127, 127, .5)", fiftypercentalpha );
parseTest( "rgba(50%, 50%, 50%, .5)", fiftypercentalpha );
parseTest( "rgba(0, 0, 0, 0)", {
expect: 4,
red: null,
green: null,
blue: null,
alpha: 0
});
parseTest("red", {
expect: 4,
red: 255,
green: 0,
blue: 0,
alpha: 1
});
parseTest("transparent", {
expect: 4,
red: null,
green: null,
blue: null,
alpha: 0
});
module( "color" );
test( "red green blue alpha Setters", function() {
var props = "red green blue alpha".split(" "),
color = jQuery.Color( [0,0,0,0] );
expect( 4 * props.length );
jQuery.each( props, function( i, fn ) {
var tv = fn==="alpha" ? 0.5 : 255,
set = color[ fn ]( tv ),
clamp = fn==="alpha" ? 1 : 255,
clamped = color[ fn ]( clamp + 1 ),
plused = color[ fn ]( "+=1" );
equal( set[ fn ](), tv, "color."+fn+"("+tv+")."+fn+"()" );
equal( clamped[ fn ](), clamp, "color."+fn+"("+(clamp+1)+") clamped at "+clamp );
equal( color[ fn ](), 0, "color."+fn+"() still 0" );
equal( plused[ fn ](), 1, "color."+fn+"(\"+=1\")" );
});
});
test( ".rgba()", function() {
var color = jQuery.Color( "black" ),
getter = color.rgba(),
set1 = color.rgba( null, 100, null, 0 ),
set2 = color.rgba([ null, null, 100, 0.5 ]),
set3 = color.rgba({ red: 300, alpha: 2 });
expect( 14 );
deepEqual( getter, color._rgba, "Returned a array has same values" );
notEqual( getter, color._rgba, "Returned a COPY of the rgba" );
testParts( set1, {
prefix: ".rgba( null, 100, null, 0 )",
red: 0,
green: 100,
blue: 0,
alpha: 0
});
testParts( set2, {
prefix: ".rgba([ null, null, 100, 0 ])",
red: 0,
green: 0,
blue: 100,
alpha: 0.5
});
testParts( set3, {
prefix: ".rgba({ red: 300, alpha: 2 })",
red: 255,
green: 0,
blue: 0,
alpha: 1
});
});
test( ".blend()", function() {
var halfwhite = jQuery.Color( "white" ).alpha( 0.5 ),
red = jQuery.Color( "red" ),
blend = halfwhite.blend( red );
expect( 8 );
testParts( blend, {
prefix: "Blending with color object: ",
red: 255,
green: 127,
blue: 127,
alpha: 1
});
testParts( halfwhite.blend("red"), {
prefix: "Using string as color: ",
red: 255,
green: 127,
blue: 127,
alpha: 1
});
});
test( ".transition() works with $.Colors", function() {
var black = jQuery.Color( "black" ),
whiteAlpha = jQuery.Color( "white" ).alpha( 0.5 ),
trans = jQuery.Color( "transparent" ),
fifty = black.transition( whiteAlpha, 0.5 );
expect( 16 );
testParts( fifty, {
prefix: "black -> whiteAlpha 0.5",
red: 127,
green: 127,
blue: 127,
alpha: 0.75
});
testParts( black.transition( trans, 0.5 ), {
prefix: "black -> transparent 0.5 ",
red: 0,
green: 0,
blue: 0,
alpha: 0.5
});
testParts( whiteAlpha.transition( trans, 0.5 ), {
prefix: "whiteAlpha -> transparent 0.5 ",
red: 255,
green: 255,
blue: 255,
alpha: 0.25
});
// fixes issue #32
testParts( jQuery.Color( 255, 0, 0, 0 ).transition( black, 0.5 ), {
prefix: "transparent red -> black 0.5",
red: 0,
green: 0,
blue: 0,
alpha: 0.5
});
});
test( ".transtion() works with strings and objects", function() {
var black = jQuery.Color( "black" );
testParts( black.transition( "white", 0.5 ), {
prefix: "black -> 'white'",
red: 127,
green: 127,
blue: 127
});
testParts( black.transition( "red", 0.5 ), {
prefix: "black -> 'red'",
red: 127,
green: 0,
blue: 0
});
testParts( black.transition({ blue: 255 }, 0.5 ), {
prefix: "black -> { blue: 255 }",
red: 0,
green: 0,
blue: 127
});
testParts( black.transition([ 200, 200, 200 ], 0.5 ), {
prefix: "black -> [ 200, 200, 200 ]",
red: 100,
green: 100,
blue: 100
});
});
test( ".is()", function() {
var red = jQuery.Color( "red" );
ok( red.is( red ), "Red is itself");
ok( red.is({ red: 255 }), "Red is equal to { red: 255 }");
ok( red.is({ saturation: 1 }), "Red is equal to { saturation: 1 }");
ok( red.is([255,0,0]), "Red is equal to [255,0,0]");
ok( red.is("red"), "Red is equal to \"red\"");
ok( !red.is("blue"), "Red is not blue");
ok( !red.is({ alpha: 0 }), "Red is not { alpha: 0 }");
});
test( ".toRgbaString()", function() {
var black = jQuery.Color( "black" ),
trans = black.alpha( 0.5 );
expect( 2 );
equal( black.toRgbaString(), "rgb(0,0,0)" );
equal( trans.toRgbaString(), "rgba(0,0,0,0.5)" );
});
test( ".toHexString()", function() {
var almostBlack = jQuery.Color( "black" ).red( 2 ).blue( 16 ),
trans = almostBlack.alpha( 0.5 );
expect( 2 );
equal( almostBlack.toHexString(), "#020010" , "to hex");
equal( trans.toHexString( true ), "#0200107f", "to hex with alpha" );
});
test( "toString() methods keep alpha intact", function() {
var trans = jQuery.Color( "transparent" ),
opaque = jQuery.Color( "red" );
expect( 4 );
trans.toRgbaString();
opaque.toRgbaString();
equal( trans.alpha(), 0, "toRgbaString()" );
equal( opaque.alpha(), 1, "toRgbaString()" );
trans.toHexString();
opaque.toHexString();
equal( trans.alpha(), 0, "toHexString()" );
equal( opaque.alpha(), 1, "toHexString()" );
});
module( "hsla" );
parseTest("hsla(180,50%,50%,0.5)", {
expect: 7,
hue: 180,
saturation: 0.5,
lightness: 0.5,
red: 64,
green: 191,
blue: 191,
alpha: 0.5
});
parseTest("hsla( 180, 50%, 50%, 1 )", {
expect: 7,
hue: 180,
saturation: 0.5,
lightness: 0.5,
red: 64,
green: 191,
blue: 191,
alpha: 1
});
parseTest("hsla( 180, 50%, 50%, .5 )", {
expect: 7,
hue: 180,
saturation: 0.5,
lightness: 0.5,
red: 64,
green: 191,
blue: 191,
alpha: 0.5
});
parseTest("hsl(72, 77%, 59%)", {
expect: 7,
hue: 72,
saturation: 0.77,
lightness: 0.59,
red: 199,
green: 231,
blue: 70,
alpha: 1
});
parseTest( jQuery.Color({ alpha: 0 }), {
expect: 7,
hue: null,
saturation: null,
lightness: null,
alpha: 0,
red: null,
green: null,
blue: null
}, "jQuery.Color({ alpha: 0 })" );
parseTest( jQuery.Color({ saturation: 0 }), {
expect: 7,
hue: null,
saturation: 0,
lightness: null,
alpha: null,
red: null,
green: null,
blue: null
}, "jQuery.Color({ saturation: 0 })" );
parseTest( jQuery.Color({ saturation: 0, alpha: 0 }), {
expect: 7,
hue: null,
saturation: 0,
lightness: null,
alpha: 0,
red: null,
green: null,
blue: null
}, "jQuery.Color({ saturation: 0, alpha: 0 })" );
test("HSLA Conversions", function() {
expect(11);
equal( jQuery.Color( "#000" ).toHslaString(), "hsl(0,0%,0%)", "HSLA value from #000");
equal( jQuery.Color( "#fff" ).toHslaString(), "hsl(0,0%,100%)", "HSLA value from #fff");
equal( jQuery.Color( "#f00" ).toHslaString(), "hsl(0,100%,50%)", "HSLA value from #f00");
equal( jQuery.Color( "#ff0" ).toHslaString(), "hsl(60,100%,50%)", "HSLA value from #ff0");
equal( jQuery.Color( "#0f0" ).toHslaString(), "hsl(120,100%,50%)", "HSLA value from #0f0");
equal( jQuery.Color( "#0ff" ).toHslaString(), "hsl(180,100%,50%)", "HSLA value from #0ff");
equal( jQuery.Color( "#00f" ).toHslaString(), "hsl(240,100%,50%)", "HSLA value from #00f");
equal( jQuery.Color( "#f0f" ).toHslaString(), "hsl(300,100%,50%)", "HSLA value from #f0f");
equal( jQuery.Color( "#7f007f" ).toHslaString(), "hsl(300,100%,25%)", "HSLA value from #7f007f");
equal( jQuery.Color( "#ff7fff" ).toHslaString(), "hsl(300,100%,75%)", "HSLA value from #ff7fff");
equal( jQuery.Color( "rgba(127,127,127,0.1)" ).toHslaString(), "hsla(0,0%,50%,0.1)", "HSLA value from rgba(127,127,127,0.1)");
});
test("HSLA Transitions", function() {
var red = jQuery.Color("red"),
desaturate = red.transition( jQuery.Color({ saturation: 0 }), 0.5 ),
hue10 = red.transition( jQuery.Color({ hue: 10 }), 0.5),
hue350 = red.transition( jQuery.Color({ hue: 350 }), 0.5),
hueWrapPos = jQuery.Color({ hue: 350 }).transition( jQuery.Color({ hue: 10 }));
testParts( desaturate, {
prefix: "red -> desaturatue 0.5",
hue: 0,
saturation: 0.5,
lightness: 0.5,
alpha: 1
});
testParts( hue10, {
prefix: "red -> hue 10 0.5",
hue: 5,
saturation: 1,
lightness: 0.5,
alpha: 1
});
testParts( hue350, {
prefix: "red -> hue 350 0.5",
hue: 355,
saturation: 1,
lightness: 0.5,
alpha: 1
});
testParts( hueWrapPos, {
prefix: " hue 350 -> hue 10 0.5",
hue: 0,
saturation: null,
lightness: null,
alpha: 1
});
});
test( "hue saturation lightness alpha Setters", function() {
var props = "hue saturation lightness alpha".split(" "),
color = jQuery.Color( [0,0,0,0] );
expect( 4 * props.length );
jQuery.each( props, function( i, fn ) {
var tv = fn === "hue" ? 359 : 0.5 ,
set = color[ fn ]( tv ),
clamp = fn === "hue" ? -360 : 1,
clamped = color[ fn ]( clamp + 1 ),
plused = color[ fn ]( "+=1" );
equal( set[ fn ](), tv, "color."+fn+"("+tv+")."+fn+"()" );
equal( clamped[ fn ](), 1, "color."+fn+"("+(clamp+1)+") clamped at 1" );
equal( color[ fn ](), 0, "color."+fn+"() still 0" );
equal( plused[ fn ](), 1, "color."+fn+"(\"+=1\")" );
});
});
test( "alpha setter leaves space as hsla", function() {
var test = jQuery.Color({hue: 0, saturation: 0, lightness: 0, alpha: 0}).alpha( 1 );
ok( test._hsla, "HSLA cache still exists after calling alpha setter" );
});
module( "animate" );
test( "animated", function() {
var el = jQuery( "<div></div>" ).appendTo( "body" ).css({ color: "#000000" });
expect( 8 );
stop();
el.animate({ color: "#ffffff" }, 1, function() {
testParts( jQuery.Color( el, "color" ), {
prefix: "Post Animated Color finished properly",
red: 255,
green: 255,
blue: 255,
alpha: 1
});
el.css( "color", "white" ).animate({ color: "#000000" }, 200).stop( true );
testParts( jQuery.Color( el, "color" ), {
prefix: "Immediately Stopped.. Animated Color didn't change",
red: 255,
green: 255,
blue: 255,
alpha: 1
});
el.remove();
start();
});
});
asyncTest( "animated documentFragment", function() {
var el = jQuery( "<div></div>" );
expect(1);
el.animate({ color: "red" }, 200, function() {
ok( true, "Animation of color on documentFragment did not fail" );
start();
});
});
test( "animate borderColor", function() {
var el = jQuery( "<div style='border: 1px solid blue;'></div>" ).appendTo( "body" );
stop();
el.animate({ borderColor: "#00f" }, {
step: function() {
testParts( jQuery.Color( el, "borderTopColor" ), {
red: 0,
green: 0,
blue: 255,
alpha: 1
});
el.stop().remove();
start();
}
});
});
test( "Setting CSS to empty string / inherit", function() {
var el = jQuery( "<div></div>" ).appendTo( "body" ).css({ color: "#fff" });
expect( 2 );
el.css( "color", "" );
equal( el[0].style.color, "", "CSS was set to empty string" );
el.css( "color", "inherit" );
ok( el[0].style.color === "" || el[0].style.color === "inherit", "Setting CSS to inherit didn't throw error" );
});
test( "Setting CSS to transparent", function() {
expect( 1 );
var parentEl = jQuery("<div></div>").appendTo("body").css({ backgroundColor: "blue" }),
el = jQuery("<div></div>").appendTo( parentEl );
el.css( "backgroundColor", "transparent" );
equal( jQuery.Color( el[ 0 ].style.backgroundColor ).alpha(), 0, "CSS was set to transparent" );
});
test( "jQuery.Color.hook() - Create new hooks for color properties", 2, function() {
// these shouldn't be there, but just in case....
delete jQuery.cssHooks.testy;
delete jQuery.fx.step.testy;
jQuery.Color.hook( "testy" );
ok( jQuery.cssHooks.testy, "testy cssHook created" );
ok( jQuery.fx.step.testy, "fx.step testy hook created" );
delete jQuery.cssHooks.testy;
delete jQuery.fx.step.testy;
});
@@ -0,0 +1,27 @@
{
"name": "jquery-sparkline",
"version": "2.1.3",
"homepage": "https://github.com/rkgrep/jquery.sparkline",
"authors": [
"Gareth Watts <gareth@omnipotent.net>"
],
"main": "dist/jquery.sparkline.js",
"license": "BSD 3",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"_release": "2.1.3",
"_resolution": {
"type": "version",
"tag": "v2.1.3",
"commit": "47b1f5a7daaa45739a75f8fd1d7c2948693d66fd"
},
"_source": "git://github.com/rkgrep/jquery.sparkline.git",
"_target": "^2.1.3",
"_originalSource": "jquery-sparkline",
"_direct": true
}
@@ -0,0 +1,324 @@
jQuery Sparkline Plugin ChangeLog
http://omnipotent.net/jquery.sparkline/
2.1.x ???
+ Fix for IE <= 9 for loading CSS when 31 stylesheets are already present
2.1.2 15/June/2013
+ Make compatible with jQuery 1.10
+ Fix intermittent "undefined error" with IE8 (issue 64)
Thanks Tim Tucker
+ Performance/minification size improvement (PR 34)
Thanks Tim Tucker
+ Prevent the plugin from being instatiated more than once (PR 37)
Thanks Tim Tucker
2.1.1 26/January/2013
+ Fix a couple of issues rendering pie charts in IE when they slices that make
up a negligible percentage of the whole chart (issue 49)
+ Don't display line chart final marker if final value is null (issue 46)
+ Make compatible with jQuery 1.9.0 (issue 60)
2.1 15/October/2012
+ Added support for Internet Explorer 10 (issue 18)
Thanks Jonathan Sampson
+ Enable the plugin to be loaded dynamically (issue 6)
Thanks joeenzminger
+ Pie charts with zero in the array of values will no longer
cause IE to display "undefined" in the page (issue 9)
+ Null values in bar charts are now correctly omitted by default (issue 23)
+ Null values in line charts would cause value highligting to be
incorrect (issue 4)
+ Raise default z-index for tooltips to ensure they always appear on top
of the chart (issue 5)
+ Allow target and performance values to be set to null for bullet charts,
omitting them from the chart (issue 3)
+ Fix clipping of highlight marker spots if min/max/final spots are disabled
in line charts (issue 31)
+ Line charts with normalRangeMin=0 will now render the normal range
correctly (issue 7)
Thanks Tim Mathewso
+ Add support for AMD based module loaders such as requirejs (PR 32)
Thanks Tim Tucker
+ Fix interquartile range calculation used by box plots (PR 10)
Thanks Claudio Riva
2.0 29/April/2012
+ jQuery.sparkline now requires jQuery 1.4.3 or later
+ All charts now support mouseover and click actions
Adds options: disableInteraction, disableTooltips, disableHighlight
+ Added sparklineClick and sparklineRegionChange events
+ Line charts have highlightSpotColor and highlightLineColor options
for controlling mouseover highligiting
+ All charts display tooltips and highlight values when moused-over by default
Adds options: tooltipContainer, tooltipOffsetX, tooltipOffsetY, tooltipFormatter,
tooltipChartTitle, tooltipFormat, tooltipPrefix, tooltipSuffix,
tooltipSkipNull, tooltipValueLookups, highlightLighten, numberFormatter,
numberDigitGroupSep, numberDecimalMark, numberDigitGroupCount
+ Fix error when all null values are fed to a line chart
Thanks Ton Voon
+ Fix off-by-one error that caused the bottom of filled line charts to
be unlevel - Thanks Sylvain Vieujot for the bug report
+ Pie charts with a single value now render correctly
Thanks Juan Manuel
+ Charts that have their dimensions specified exactly in pixels may see
improved performance
Thanks Sean Carpenter
+ Coloured spots may be added to some or all values on a line chart now using
the new valueSpots option
Thanks Russ Beebe for the suggestion
+ Bar and tristates charts now support using range of values for the colorMap
option - Eg. allows all bars with values betweeen 10 and 20 to be green
+ Pie charts may now have a border using the borderWidth and borderColor
options - Thanks Michael Mior for the suggestion
+ Added a disableHiddenCheck option - If you know your charts will never be
in a hidden block (display:none) at time of rendering, disabling this check
may improve performance
+ Reduce number of DOM interactions when rendering charts in Internet Explorer
to increase render performance
+ Bar charts may now have stacked values by providing an array of arrays
or by passing a comma and colon delimited series of values (eg. "1:2:3,2:3:1")
+ Fix a bug where some spots would be drawn in the wrong position on line
charts if the x values were supplied as well as the y
+ Fix a bug causing hidden composite sparklines to fail to render
once $.sparkline_display_visible() is called.
+ If there are multiple calls to sparkline() on a hidden element, the plugin
will now only render the most recent one when the element becomes visible,
saving CPU time for the same visual result.
+ If a hidden sparkline waiting to be rendered is removed from the DOM
via jQuery's .remove() or .html() etc methods then it will be
removed from the pending queue the next time $.sparkline_display_visible()
is called, preventing a memory leak.
+ Add the $.range_map() and $.spformat() methods
1.6 30/November/2010
+ Allow options to be set as tag attributes, as well as passed in to the sparkline
function as an argument. See new enableTagOptions and tagOptionPrefix options.
+ Added alternate methods of passing values in via HTML.
Can now include inline values in a comment, or pass values in as a values
attribute on the tag:
<span class="sparkline"><!-- 1,2,3,4,5 --></span>
<span class="sparkline" values="1,2,3,4,5"></span>
+ bullet graphs now handle non-integer values correctly
+ Added drawNormalOnTop option to line charts to force the normal
range to be drawn over the top of the line chart's fill color
+ Detect if an element is not inserted into the DOM so that $.sparkline_display_visible()
will function correctly after it's later inserted.
+ Remove the use of the Array indexOf prototype that was added to IE to avoid
conflicts with other libraries.
+ Default settings are now exposed as $.fn.sparkline.defaults allowing
script-wide changes to be made instead of passing them to the sparkline function
on each call
1.5.1 01/March/2010
+ 1 character typo fix for IE - Thanks to Daniel Kenyon-Jones for the heads up
1.5 26/February/2010
+ Very small pie slices could fill the whole chart in IE
Thanks to Peter Doel for catching and fixing it
+ Added chartRangeClip option to force values outside of chartRangeMin/chartRangeMax
to be clipped
+ Added chartRangeMinX/chartRangeMaxX for line charts
+ Allow chart types other than line chart to be used as composites.
+ colorMap may now pass null as a colour to omit that bar from display entirely
+ colorMap may now be passed as an Array of values allowing the colour of each
bar to be specified individually, rather than mapping by value
+ Added nullColor option to bar charts to force null values to show up as a thin line
+ Performance improvements with IE
1.4.3 14/September/2009
+ Updated default pie chart colours - Thanks Liel Dulev
+ Null values can now be supplied to line and bar charts
(use 'null' as the value) - Thanks to Ed Blachman for
testing/debugging help
+ Added colorMap option for bar charts
+ Added lineWidth option for line charts - Can be an integer or a float
(try 1.5 or 2)
1.4.2 25/April/2009
+ Fixed rendering of circular spots on line charts
for Internet Explorer 8
1.4.1 27/March/2009
+ Fixed minor off-by-1-pixel display glitch with IE
+ Improved compatibilty with jQuery 1.3 which could cause some sparklines
not to be rendered in certain situations
1.4 25/February/2009
+ Added the box plot chart type
+ Fixed a canvas rendering issue that would display some charts with
fuzzy lines
+ Fixed error in bar charts which would causes bars to be too short.
+ Couple of other minor bug fixes
1.3 25/January/2009
+ Sparklines can't be automatically displayed into hidden elements (ie.
with display:none) - Added a $.sparkline_display_visible() function
to render any sparklines that were generated while a tag was
hidden
+ Fixed positioning issues where sparklines would be displayed a few
pixels offset from their containers in some browsers
+ Made a first attempt at IE8 support. IE8 beta 2 seems to
have some vml related bugs though so having more than one sparkline
on a line doesn't work correctly, nor do the markers on line charts
+ Misc other bug fixes
+ Updated the web site with a new look
1.2.1 24/November/2008
+ Pie chart bug fixes: Divide by zero error resolved
and IE rendering issue if a pie slice is equal to 0
Thanks to Hubert Mandeville for a patch fixing both issues
1.2 - 19/November/2008
+ Fixed positioning of min/max line markers for fixed range graphs
(thanks to Stéphane Busso)
+ Fixed rendering of bar charts with negative values
+ All values in a bar chart have a height now (min values used to
have height = 0)
+ Added zeroColor option for bar charts which allows assignment of
a different color for values that are equal to zero
+ Line charts can now specify both x and y values if required in one of
three ways:
a) Inline with HTML with values interleaved:
x1:y1,x2:y2,x3:y3
eg. <span class="linechart">1:10,5:8,7:10</span>
b) Programatically using an x,y array for each value:
$('#mychart').sparkline([ [1,10], [5,8], [7,10] ]);
c) Programatically using a separate array for the x values:
$('#mychart').sparkline( [10,8,10], { xvalues: [1,5,7] });
+ Added chartRangeMin and chartRangeMax to line, bar and discrete graphs
This allows you to artificialy fix the min/max values for the graph
so that multiple graphs can share the same scale.
+ Added defaultPixelsPerValue option to specify how many pixels wide
each value should be in a dynamically sized line graph
+ Added offset option to piecharts - Takes a positive or negative degree
offset to start drawing the chart from.
1.1 - 29/July/2008
+ Added minSpotColor and maxSpotColor to line charts - If set then spot
markers are placed at the cordinates of the minimum and maximum values.
+ Added normalRangeMin and normalRangeMax to line charts - If set then
a normalRangeColor band will be drawn on the graph
+ Added chart compositing - Applying another chart to a DOM element with
an option of composite: true will cause the second (or more) chart to be
overlayed on the first rather than replacing it.
+ Added optional colorMap option to tristate chart - This allows specific
colors to be supplied for specific values
+ Added discrete chart type - Uses fixed size discrete vertical lines to mark
each values in a series
+ Added bullet graph type - Implementation of Stephen Few's bullet graphs
+ Added pie chart type
+ Improved auto height option to match the line height of the containing
element
+ Fixed some off by one positioning errors
+ Reduced the default radius of spot markers from 2 to 1.5 pixels
1.0 - 17/July/2008
+ Initial Release
@@ -0,0 +1,41 @@
SRC_DIR = src
DIST_DIR = dist
COMPILER ?= `which uglifyjs` --no-copyright
SRC_FILES = $(SRC_DIR)/header.js\
$(SRC_DIR)/defaults.js\
$(SRC_DIR)/utils.js\
$(SRC_DIR)/simpledraw.js\
$(SRC_DIR)/rangemap.js\
$(SRC_DIR)/interact.js\
$(SRC_DIR)/base.js\
$(SRC_DIR)/chart-line.js\
$(SRC_DIR)/chart-bar.js\
$(SRC_DIR)/chart-tristate.js\
$(SRC_DIR)/chart-discrete.js\
$(SRC_DIR)/chart-bullet.js\
$(SRC_DIR)/chart-pie.js\
$(SRC_DIR)/chart-box.js\
$(SRC_DIR)/vcanvas-base.js\
$(SRC_DIR)/vcanvas-canvas.js\
$(SRC_DIR)/vcanvas-vml.js\
$(SRC_DIR)/footer.js
VERSION = $(shell cat version.txt)
all: jqs-gzip jqs-min-gzip Changelog.txt
jqs: ${SRC_FILES}
cat ${SRC_FILES} | sed 's/@VERSION@/${VERSION}/' >${DIST_DIR}/jquery.sparkline.js
jqs-min: jqs
cat minheader.txt | sed 's/@VERSION@/${VERSION}/' >dist/jquery.sparkline.min.js
${COMPILER} dist/jquery.sparkline.js >>dist/jquery.sparkline.min.js
jqs-gzip: jqs
gzip -9 < dist/jquery.sparkline.js >dist/jquery.sparkline.js.gz
jqs-min-gzip: jqs-min
gzip -9 < dist/jquery.sparkline.min.js >dist/jquery.sparkline.min.js.gz
@@ -0,0 +1,19 @@
jQuery Sparklines
=================
This jQuery plugin makes it easy to generate a number of different types
of sparklines directly in the browser, using online a line of two of HTML
and Javascript.
The plugin has no dependencies other than jQuery and works with all modern
browsers and also Internet Explorer 6 and later (excanvas is not required
for IE support).
See the [jQuery Sparkline project page](http://omnipotent.net/jquery.sparkline/)
for live examples and documentation.
## License
Released under the New BSD License
(c) Splunk, Inc 2012
@@ -0,0 +1,17 @@
{
"name": "jquery-sparkline",
"version": "2.1.3",
"homepage": "https://github.com/rkgrep/jquery.sparkline",
"authors": [
"Gareth Watts <gareth@omnipotent.net>"
],
"main": "dist/jquery.sparkline.js",
"license": "BSD 3",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
/* jquery.sparkline @VERSION@ - http://omnipotent.net/jquery.sparkline/
** Licensed under the New BSD License - see above site for details */
@@ -0,0 +1,34 @@
{
"name": "sparkline",
"title": "jQuery Sparkline",
"description": "Easily generate small, inline sparkline charts directly in the browser",
"keywords": [
"canvas",
"charts",
"graphics",
"graphing",
"graphs",
"sparklines",
"ui",
"vml"
],
"version": "2.1.2",
"author": {
"name": "Gareth Watts",
"url": "http://gwatts.com/"
},
"licenses": [
{
"type": "BSD-3-Clause",
"url": "http://opensource.org/licenses/BSD-3-Clause"
}
],
"bugs": "https://github.com/gwatts/jquery.sparkline/issues",
"homepage": "http://omnipotent.net/jquery.sparkline/",
"demo": "http://omnipotent.net/jquery.sparkline/",
"docs": "http://omnipotent.net/jquery.sparkline/#s-docs",
"download": "http://omnipotent.net/jquery.sparkline/#s-download",
"dependencies": {
"jquery": ">=1.4.3"
}
}
@@ -0,0 +1,415 @@
initStyles = function() {
addCSS(defaultStyles);
};
$(initStyles);
pending = [];
$.fn.sparkline = function (userValues, userOptions) {
return this.each(function () {
var options = new $.fn.sparkline.options(this, userOptions),
$this = $(this),
render, i;
render = function () {
var values, width, height, tmp, mhandler, sp, vals;
if (userValues === 'html' || userValues === undefined) {
vals = this.getAttribute(options.get('tagValuesAttribute'));
if (vals === undefined || vals === null) {
vals = $this.html();
}
values = vals.replace(/(^\s*<!--)|(-->\s*$)|\s+/g, '').split(',');
} else {
values = userValues;
}
width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width');
if (options.get('height') === 'auto') {
if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) {
// must be a better way to get the line height
tmp = document.createElement('span');
tmp.innerHTML = 'a';
$this.html(tmp);
height = $(tmp).innerHeight() || $(tmp).height();
$(tmp).remove();
tmp = null;
}
} else {
height = options.get('height');
}
if (!options.get('disableInteraction')) {
mhandler = $.data(this, '_jqs_mhandler');
if (!mhandler) {
mhandler = new MouseHandler(this, options);
$.data(this, '_jqs_mhandler', mhandler);
} else if (!options.get('composite')) {
mhandler.reset();
}
} else {
mhandler = false;
}
if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) {
if (!$.data(this, '_jqs_errnotify')) {
alert('Attempted to attach a composite sparkline to an element with no existing sparkline');
$.data(this, '_jqs_errnotify', true);
}
return;
}
sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height);
sp.render();
if (mhandler) {
mhandler.registerSparkline(sp);
}
};
if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || !$(this).parents('body').length) {
if (!options.get('composite') && $.data(this, '_jqs_pending')) {
// remove any existing references to the element
for (i = pending.length; i; i--) {
if (pending[i - 1][0] == this) {
pending.splice(i - 1, 1);
}
}
}
pending.push([this, render]);
$.data(this, '_jqs_pending', true);
} else {
render.call(this);
}
});
};
$.fn.sparkline.defaults = getDefaults();
$.sparkline_display_visible = function () {
var el, i, pl;
var done = [];
for (i = 0, pl = pending.length; i < pl; i++) {
el = pending[i][0];
if ($(el).is(':visible') && !$(el).parents().is(':hidden')) {
pending[i][1].call(el);
$.data(pending[i][0], '_jqs_pending', false);
done.push(i);
} else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) {
// element has been inserted and removed from the DOM
// If it was not yet inserted into the dom then the .data request
// will return true.
// removing from the dom causes the data to be removed.
$.data(pending[i][0], '_jqs_pending', false);
done.push(i);
}
}
for (i = done.length; i; i--) {
pending.splice(done[i - 1], 1);
}
};
/**
* User option handler
*/
$.fn.sparkline.options = createClass({
init: function (tag, userOptions) {
var extendedOptions, defaults, base, tagOptionType;
this.userOptions = userOptions = userOptions || {};
this.tag = tag;
this.tagValCache = {};
defaults = $.fn.sparkline.defaults;
base = defaults.common;
this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);
tagOptionType = this.getTagSetting('type');
if (tagOptionType === UNSET_OPTION) {
extendedOptions = defaults[userOptions.type || base.type];
} else {
extendedOptions = defaults[tagOptionType];
}
this.mergedOptions = $.extend({}, base, extendedOptions, userOptions);
},
getTagSetting: function (key) {
var prefix = this.tagOptionsPrefix,
val, i, pairs, keyval;
if (prefix === false || prefix === undefined) {
return UNSET_OPTION;
}
if (this.tagValCache.hasOwnProperty(key)) {
val = this.tagValCache.key;
} else {
val = this.tag.getAttribute(prefix + key);
if (val === undefined || val === null) {
val = UNSET_OPTION;
} else if (val.substr(0, 1) === '[') {
val = val.substr(1, val.length - 2).split(',');
for (i = val.length; i--;) {
val[i] = normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g, ''));
}
} else if (val.substr(0, 1) === '{') {
pairs = val.substr(1, val.length - 2).split(',');
val = {};
for (i = pairs.length; i--;) {
keyval = pairs[i].split(':', 2);
val[keyval[0].replace(/(^\s*)|(\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g, ''));
}
} else {
val = normalizeValue(val);
}
this.tagValCache.key = val;
}
return val;
},
get: function (key, defaultval) {
var tagOption = this.getTagSetting(key),
result;
if (tagOption !== UNSET_OPTION) {
return tagOption;
}
return (result = this.mergedOptions[key]) === undefined ? defaultval : result;
}
});
$.fn.sparkline._base = createClass({
disabled: false,
init: function (el, values, options, width, height) {
this.el = el;
this.$el = $(el);
this.values = values;
this.options = options;
this.width = width;
this.height = height;
this.currentRegion = undefined;
},
/**
* Setup the canvas
*/
initTarget: function () {
var interactive = !this.options.get('disableInteraction');
if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) {
this.disabled = true;
} else {
this.canvasWidth = this.target.pixelWidth;
this.canvasHeight = this.target.pixelHeight;
}
},
/**
* Actually render the chart to the canvas
*/
render: function () {
if (this.disabled) {
this.el.innerHTML = '';
return false;
}
return true;
},
/**
* Return a region id for a given x/y co-ordinate
*/
getRegion: function (x, y) {
},
/**
* Highlight an item based on the moused-over x,y co-ordinate
*/
setRegionHighlight: function (el, x, y) {
var currentRegion = this.currentRegion,
highlightEnabled = !this.options.get('disableHighlight'),
newRegion;
if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {
return null;
}
newRegion = this.getRegion(el, x, y);
if (currentRegion !== newRegion) {
if (currentRegion !== undefined && highlightEnabled) {
this.removeHighlight();
}
this.currentRegion = newRegion;
if (newRegion !== undefined && highlightEnabled) {
this.renderHighlight();
}
return true;
}
return false;
},
/**
* Reset any currently highlighted item
*/
clearRegionHighlight: function () {
if (this.currentRegion !== undefined) {
this.removeHighlight();
this.currentRegion = undefined;
return true;
}
return false;
},
renderHighlight: function () {
this.changeHighlight(true);
},
removeHighlight: function () {
this.changeHighlight(false);
},
changeHighlight: function (highlight) {},
/**
* Fetch the HTML to display as a tooltip
*/
getCurrentRegionTooltip: function () {
var options = this.options,
header = '',
entries = [],
fields, formats, formatlen, fclass, text, i,
showFields, showFieldsKey, newFields, fv,
formatter, format, fieldlen, j;
if (this.currentRegion === undefined) {
return '';
}
fields = this.getCurrentRegionFields();
formatter = options.get('tooltipFormatter');
if (formatter) {
return formatter(this, options, fields);
}
if (options.get('tooltipChartTitle')) {
header += '<div class="jqs jqstitle">' + options.get('tooltipChartTitle') + '</div>\n';
}
formats = this.options.get('tooltipFormat');
if (!formats) {
return '';
}
if (!$.isArray(formats)) {
formats = [formats];
}
if (!$.isArray(fields)) {
fields = [fields];
}
showFields = this.options.get('tooltipFormatFieldlist');
showFieldsKey = this.options.get('tooltipFormatFieldlistKey');
if (showFields && showFieldsKey) {
// user-selected ordering of fields
newFields = [];
for (i = fields.length; i--;) {
fv = fields[i][showFieldsKey];
if ((j = $.inArray(fv, showFields)) != -1) {
newFields[j] = fields[i];
}
}
fields = newFields;
}
formatlen = formats.length;
fieldlen = fields.length;
for (i = 0; i < formatlen; i++) {
format = formats[i];
if (typeof format === 'string') {
format = new SPFormat(format);
}
fclass = format.fclass || 'jqsfield';
for (j = 0; j < fieldlen; j++) {
if (!fields[j].isNull || !options.get('tooltipSkipNull')) {
$.extend(fields[j], {
prefix: options.get('tooltipPrefix'),
suffix: options.get('tooltipSuffix')
});
text = format.render(fields[j], options.get('tooltipValueLookups'), options);
entries.push('<div class="' + fclass + '">' + text + '</div>');
}
}
}
if (entries.length) {
return header + entries.join('\n');
}
return '';
},
getCurrentRegionFields: function () {},
calcHighlightColor: function (color, options) {
var highlightColor = options.get('highlightColor'),
lighten = options.get('highlightLighten'),
parse, mult, rgbnew, i;
if (highlightColor) {
return highlightColor;
}
if (lighten) {
// extract RGB values
parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);
if (parse) {
rgbnew = [];
mult = color.length === 4 ? 16 : 1;
for (i = 0; i < 3; i++) {
rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);
}
return 'rgb(' + rgbnew.join(',') + ')';
}
}
return color;
}
});
barHighlightMixin = {
changeHighlight: function (highlight) {
var currentRegion = this.currentRegion,
target = this.target,
shapeids = this.regionShapes[currentRegion],
newShapes;
// will be null if the region value was null
if (shapeids) {
newShapes = this.renderRegion(currentRegion, highlight);
if ($.isArray(newShapes) || $.isArray(shapeids)) {
target.replaceWithShapes(shapeids, newShapes);
this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) {
return newShape.id;
});
} else {
target.replaceWithShape(shapeids, newShapes);
this.regionShapes[currentRegion] = newShapes.id;
}
}
},
render: function () {
var values = this.values,
target = this.target,
regionShapes = this.regionShapes,
shapes, ids, i, j;
if (!this.cls._super.render.call(this)) {
return;
}
for (i = values.length; i--;) {
shapes = this.renderRegion(i);
if (shapes) {
if ($.isArray(shapes)) {
ids = [];
for (j = shapes.length; j--;) {
shapes[j].append();
ids.push(shapes[j].id);
}
regionShapes[i] = ids;
} else {
shapes.append();
regionShapes[i] = shapes.id; // store just the shapeid
}
} else {
// null value
regionShapes[i] = null;
}
}
target.render();
}
};
@@ -0,0 +1,256 @@
/**
* Bar charts
*/
$.fn.sparkline.bar = bar = createClass($.fn.sparkline._base, barHighlightMixin, {
type: 'bar',
init: function (el, values, options, width, height) {
var barWidth = parseInt(options.get('barWidth'), 10),
barSpacing = parseInt(options.get('barSpacing'), 10),
chartRangeMin = options.get('chartRangeMin'),
chartRangeMax = options.get('chartRangeMax'),
chartRangeClip = options.get('chartRangeClip'),
stackMin = Infinity,
stackMax = -Infinity,
isStackString, groupMin, groupMax, stackRanges,
numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax,
stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;
bar._super.init.call(this, el, values, options, width, height);
// scan values to determine whether to stack bars
for (i = 0, vlen = values.length; i < vlen; i++) {
val = values[i];
isStackString = typeof(val) === 'string' && val.indexOf(':') > -1;
if (isStackString || $.isArray(val)) {
stacked = true;
if (isStackString) {
val = values[i] = normalizeValues(val.split(':'));
}
val = remove(val, null); // min/max will treat null as zero
groupMin = Math.min.apply(Math, val);
groupMax = Math.max.apply(Math, val);
if (groupMin < stackMin) {
stackMin = groupMin;
}
if (groupMax > stackMax) {
stackMax = groupMax;
}
}
}
this.stacked = stacked;
this.regionShapes = {};
this.barWidth = barWidth;
this.barSpacing = barSpacing;
this.totalBarWidth = barWidth + barSpacing;
this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
this.initTarget();
if (chartRangeClip) {
clipMin = chartRangeMin === undefined ? -Infinity : chartRangeMin;
clipMax = chartRangeMax === undefined ? Infinity : chartRangeMax;
}
numValues = [];
stackRanges = stacked ? [] : numValues;
var stackTotals = [];
var stackRangesNeg = [];
for (i = 0, vlen = values.length; i < vlen; i++) {
if (stacked) {
vlist = values[i];
values[i] = svals = [];
stackTotals[i] = 0;
stackRanges[i] = stackRangesNeg[i] = 0;
for (j = 0, slen = vlist.length; j < slen; j++) {
val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];
if (val !== null) {
if (val > 0) {
stackTotals[i] += val;
}
if (stackMin < 0 && stackMax > 0) {
if (val < 0) {
stackRangesNeg[i] += Math.abs(val);
} else {
stackRanges[i] += val;
}
} else {
stackRanges[i] += Math.abs(val - (val < 0 ? stackMax : stackMin));
}
numValues.push(val);
}
}
} else {
val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];
val = values[i] = normalizeValue(val);
if (val !== null) {
numValues.push(val);
}
}
}
this.max = max = Math.max.apply(Math, numValues);
this.min = min = Math.min.apply(Math, numValues);
this.stackMax = stackMax = stacked ? Math.max.apply(Math, stackTotals) : max;
this.stackMin = stackMin = stacked ? Math.min.apply(Math, numValues) : min;
if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < min)) {
min = options.get('chartRangeMin');
}
if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > max)) {
max = options.get('chartRangeMax');
}
this.zeroAxis = zeroAxis = options.get('zeroAxis', true);
if (min <= 0 && max >= 0 && zeroAxis) {
xaxisOffset = 0;
} else if (zeroAxis == false) {
xaxisOffset = min;
} else if (min > 0) {
xaxisOffset = min;
} else {
xaxisOffset = max;
}
this.xaxisOffset = xaxisOffset;
range = stacked ? (Math.max.apply(Math, stackRanges) + Math.max.apply(Math, stackRangesNeg)) : max - min;
// as we plot zero/min values a single pixel line, we add a pixel to all other
// values - Reduce the effective canvas size to suit
this.canvasHeightEf = (zeroAxis && min < 0) ? this.canvasHeight - 2 : this.canvasHeight - 1;
if (min < xaxisOffset) {
yMaxCalc = (stacked && max >= 0) ? stackMax : max;
yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;
if (yoffset !== Math.ceil(yoffset)) {
this.canvasHeightEf -= 2;
yoffset = Math.ceil(yoffset);
}
} else {
yoffset = this.canvasHeight;
}
this.yoffset = yoffset;
if ($.isArray(options.get('colorMap'))) {
this.colorMapByIndex = options.get('colorMap');
this.colorMapByValue = null;
} else {
this.colorMapByIndex = null;
this.colorMapByValue = options.get('colorMap');
if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
this.colorMapByValue = new RangeMap(this.colorMapByValue);
}
}
this.range = range;
},
getRegion: function (el, x, y) {
var result = Math.floor(x / this.totalBarWidth);
return (result < 0 || result >= this.values.length) ? undefined : result;
},
getCurrentRegionFields: function () {
var currentRegion = this.currentRegion,
values = ensureArray(this.values[currentRegion]),
result = [],
value, i;
for (i = values.length; i--;) {
value = values[i];
result.push({
isNull: value === null,
value: value,
color: this.calcColor(i, value, currentRegion),
offset: currentRegion
});
}
return result;
},
calcColor: function (stacknum, value, valuenum) {
var colorMapByIndex = this.colorMapByIndex,
colorMapByValue = this.colorMapByValue,
options = this.options,
color, newColor;
if (this.stacked) {
color = options.get('stackedBarColor');
} else {
color = (value < 0) ? options.get('negBarColor') : options.get('barColor');
}
if (value === 0 && options.get('zeroColor') !== undefined) {
color = options.get('zeroColor');
}
if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
color = newColor;
} else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
color = colorMapByIndex[valuenum];
}
return $.isArray(color) ? color[stacknum % color.length] : color;
},
/**
* Render bar(s) for a region
*/
renderRegion: function (valuenum, highlight) {
var vals = this.values[valuenum],
options = this.options,
xaxisOffset = this.xaxisOffset,
result = [],
range = this.range,
stacked = this.stacked,
target = this.target,
x = valuenum * this.totalBarWidth,
canvasHeightEf = this.canvasHeightEf,
yoffset = this.yoffset,
y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;
vals = $.isArray(vals) ? vals : [vals];
valcount = vals.length;
val = vals[0];
isNull = all(null, vals);
allMin = all(xaxisOffset, vals, true);
if (isNull) {
if (options.get('nullColor')) {
color = highlight ? options.get('nullColor') : this.calcHighlightColor(options.get('nullColor'), options);
y = (yoffset > 0) ? yoffset - 1 : yoffset;
return target.drawRect(x, y, this.barWidth - 1, 0, color, color);
} else {
return undefined;
}
}
yoffsetNeg = yoffset;
for (i = 0; i < valcount; i++) {
val = vals[i];
if (stacked && val === xaxisOffset) {
if (!allMin || minPlotted) {
continue;
}
minPlotted = true;
}
if (range > 0) {
height = Math.floor(canvasHeightEf * ((Math.abs(val - xaxisOffset) / range))) + 1;
} else {
height = 1;
}
if (val < xaxisOffset || (val === xaxisOffset && yoffset === 0)) {
y = yoffsetNeg;
yoffsetNeg += height;
} else {
y = yoffset - height;
yoffset -= height;
}
color = this.calcColor(i, val, valuenum);
if (highlight) {
color = this.calcHighlightColor(color, options);
}
result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));
}
if (result.length === 1) {
return result[0];
}
return result;
}
});
@@ -0,0 +1,186 @@
/**
* Box plots
*/
$.fn.sparkline.box = box = createClass($.fn.sparkline._base, {
type: 'box',
init: function (el, values, options, width, height) {
box._super.init.call(this, el, values, options, width, height);
this.values = $.map(values, Number);
this.width = options.get('width') === 'auto' ? '4.0em' : width;
this.initTarget();
if (!this.values.length) {
this.disabled = 1;
}
},
/**
* Simulate a single region
*/
getRegion: function () {
return 1;
},
getCurrentRegionFields: function () {
var result = [
{ field: 'lq', value: this.quartiles[0] },
{ field: 'med', value: this.quartiles[1] },
{ field: 'uq', value: this.quartiles[2] }
];
if (this.loutlier !== undefined) {
result.push({ field: 'lo', value: this.loutlier});
}
if (this.routlier !== undefined) {
result.push({ field: 'ro', value: this.routlier});
}
if (this.lwhisker !== undefined) {
result.push({ field: 'lw', value: this.lwhisker});
}
if (this.rwhisker !== undefined) {
result.push({ field: 'rw', value: this.rwhisker});
}
return result;
},
render: function () {
var target = this.target,
values = this.values,
vlen = values.length,
options = this.options,
canvasWidth = this.canvasWidth,
canvasHeight = this.canvasHeight,
minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),
maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),
canvasLeft = 0,
lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,
size, unitSize;
if (!box._super.render.call(this)) {
return;
}
if (options.get('raw')) {
if (options.get('showOutliers') && values.length > 5) {
loutlier = values[0];
lwhisker = values[1];
q1 = values[2];
q2 = values[3];
q3 = values[4];
rwhisker = values[5];
routlier = values[6];
} else {
lwhisker = values[0];
q1 = values[1];
q2 = values[2];
q3 = values[3];
rwhisker = values[4];
}
} else {
values.sort(function (a, b) { return a - b; });
q1 = quartile(values, 1);
q2 = quartile(values, 2);
q3 = quartile(values, 3);
iqr = q3 - q1;
if (options.get('showOutliers')) {
lwhisker = rwhisker = undefined;
for (i = 0; i < vlen; i++) {
if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {
lwhisker = values[i];
}
if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {
rwhisker = values[i];
}
}
loutlier = values[0];
routlier = values[vlen - 1];
} else {
lwhisker = values[0];
rwhisker = values[vlen - 1];
}
}
this.quartiles = [q1, q2, q3];
this.lwhisker = lwhisker;
this.rwhisker = rwhisker;
this.loutlier = loutlier;
this.routlier = routlier;
unitSize = canvasWidth / (maxValue - minValue + 1);
if (options.get('showOutliers')) {
canvasLeft = Math.ceil(options.get('spotRadius'));
canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));
unitSize = canvasWidth / (maxValue - minValue + 1);
if (loutlier < lwhisker) {
target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,
canvasHeight / 2,
options.get('spotRadius'),
options.get('outlierLineColor'),
options.get('outlierFillColor')).append();
}
if (routlier > rwhisker) {
target.drawCircle((routlier - minValue) * unitSize + canvasLeft,
canvasHeight / 2,
options.get('spotRadius'),
options.get('outlierLineColor'),
options.get('outlierFillColor')).append();
}
}
// box
target.drawRect(
Math.round((q1 - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight * 0.1),
Math.round((q3 - q1) * unitSize),
Math.round(canvasHeight * 0.8),
options.get('boxLineColor'),
options.get('boxFillColor')).append();
// left whisker
target.drawLine(
Math.round((lwhisker - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight / 2),
Math.round((q1 - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight / 2),
options.get('lineColor')).append();
target.drawLine(
Math.round((lwhisker - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight / 4),
Math.round((lwhisker - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight - canvasHeight / 4),
options.get('whiskerColor')).append();
// right whisker
target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight / 2),
Math.round((q3 - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight / 2),
options.get('lineColor')).append();
target.drawLine(
Math.round((rwhisker - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight / 4),
Math.round((rwhisker - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight - canvasHeight / 4),
options.get('whiskerColor')).append();
// median line
target.drawLine(
Math.round((q2 - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight * 0.1),
Math.round((q2 - minValue) * unitSize + canvasLeft),
Math.round(canvasHeight * 0.9),
options.get('medianColor')).append();
if (options.get('target')) {
size = Math.ceil(options.get('spotRadius'));
target.drawLine(
Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
Math.round((canvasHeight / 2) - size),
Math.round((options.get('target') - minValue) * unitSize + canvasLeft),
Math.round((canvasHeight / 2) + size),
options.get('targetColor')).append();
target.drawLine(
Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),
Math.round(canvasHeight / 2),
Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),
Math.round(canvasHeight / 2),
options.get('targetColor')).append();
}
target.render();
}
});
@@ -0,0 +1,131 @@
/**
* Bullet charts
*/
$.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {
type: 'bullet',
init: function (el, values, options, width, height) {
var min, max, vals;
bullet._super.init.call(this, el, values, options, width, height);
// values: target, performance, range1, range2, range3
this.values = values = normalizeValues(values);
// target or performance could be null
vals = values.slice();
vals[0] = vals[0] === null ? vals[2] : vals[0];
vals[1] = values[1] === null ? vals[2] : vals[1];
min = Math.min.apply(Math, values);
max = Math.max.apply(Math, values);
if (options.get('base') === undefined) {
min = min < 0 ? min : 0;
} else {
min = options.get('base');
}
this.min = min;
this.max = max;
this.range = max - min;
this.shapes = {};
this.valueShapes = {};
this.regiondata = {};
this.width = width = options.get('width') === 'auto' ? '4.0em' : width;
this.target = this.$el.simpledraw(width, height, options.get('composite'));
if (!values.length) {
this.disabled = true;
}
this.initTarget();
},
getRegion: function (el, x, y) {
var shapeid = this.target.getShapeAt(el, x, y);
return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
},
getCurrentRegionFields: function () {
var currentRegion = this.currentRegion;
return {
fieldkey: currentRegion.substr(0, 1),
value: this.values[currentRegion.substr(1)],
region: currentRegion
};
},
changeHighlight: function (highlight) {
var currentRegion = this.currentRegion,
shapeid = this.valueShapes[currentRegion],
shape;
delete this.shapes[shapeid];
switch (currentRegion.substr(0, 1)) {
case 'r':
shape = this.renderRange(currentRegion.substr(1), highlight);
break;
case 'p':
shape = this.renderPerformance(highlight);
break;
case 't':
shape = this.renderTarget(highlight);
break;
}
this.valueShapes[currentRegion] = shape.id;
this.shapes[shape.id] = currentRegion;
this.target.replaceWithShape(shapeid, shape);
},
renderRange: function (rn, highlight) {
var rangeval = this.values[rn],
rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),
color = this.options.get('rangeColors')[rn - 2];
if (highlight) {
color = this.calcHighlightColor(color, this.options);
}
return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);
},
renderPerformance: function (highlight) {
var perfval = this.values[1],
perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),
color = this.options.get('performanceColor');
if (highlight) {
color = this.calcHighlightColor(color, this.options);
}
return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,
Math.round(this.canvasHeight * 0.4) - 1, color, color);
},
renderTarget: function (highlight) {
var targetval = this.values[0],
x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),
targettop = Math.round(this.canvasHeight * 0.10),
targetheight = this.canvasHeight - (targettop * 2),
color = this.options.get('targetColor');
if (highlight) {
color = this.calcHighlightColor(color, this.options);
}
return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);
},
render: function () {
var vlen = this.values.length,
target = this.target,
i, shape;
if (!bullet._super.render.call(this)) {
return;
}
for (i = 2; i < vlen; i++) {
shape = this.renderRange(i).append();
this.shapes[shape.id] = 'r' + i;
this.valueShapes['r' + i] = shape.id;
}
if (this.values[1] !== null) {
shape = this.renderPerformance().append();
this.shapes[shape.id] = 'p1';
this.valueShapes.p1 = shape.id;
}
if (this.values[0] !== null) {
shape = this.renderTarget().append();
this.shapes[shape.id] = 't0';
this.valueShapes.t0 = shape.id;
}
target.render();
}
});
@@ -0,0 +1,66 @@
/**
* Discrete charts
*/
$.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {
type: 'discrete',
init: function (el, values, options, width, height) {
discrete._super.init.call(this, el, values, options, width, height);
this.regionShapes = {};
this.values = values = $.map(values, Number);
this.min = Math.min.apply(Math, values);
this.max = Math.max.apply(Math, values);
this.range = this.max - this.min;
this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;
this.interval = Math.floor(width / values.length);
this.itemWidth = width / values.length;
if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {
this.min = options.get('chartRangeMin');
}
if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {
this.max = options.get('chartRangeMax');
}
this.initTarget();
if (this.target) {
this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');
}
},
getRegion: function (el, x, y) {
return Math.floor(x / this.itemWidth);
},
getCurrentRegionFields: function () {
var currentRegion = this.currentRegion;
return {
isNull: this.values[currentRegion] === undefined,
value: this.values[currentRegion],
offset: currentRegion
};
},
renderRegion: function (valuenum, highlight) {
var values = this.values,
options = this.options,
min = this.min,
max = this.max,
range = this.range,
interval = this.interval,
target = this.target,
canvasHeight = this.canvasHeight,
lineHeight = this.lineHeight,
pheight = canvasHeight - lineHeight,
ytop, val, color, x;
val = clipval(values[valuenum], min, max);
x = valuenum * interval;
ytop = Math.round(pheight - pheight * ((val - min) / range));
color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');
if (highlight) {
color = this.calcHighlightColor(color, options);
}
return target.drawLine(x, ytop, x, ytop + lineHeight, color);
}
});
@@ -0,0 +1,350 @@
/**
* Line charts
*/
$.fn.sparkline.line = line = createClass($.fn.sparkline._base, {
type: 'line',
init: function (el, values, options, width, height) {
line._super.init.call(this, el, values, options, width, height);
this.vertices = [];
this.regionMap = [];
this.xvalues = [];
this.yvalues = [];
this.yminmax = [];
this.hightlightSpotId = null;
this.lastShapeId = null;
this.initTarget();
},
getRegion: function (el, x, y) {
var i,
regionMap = this.regionMap; // maps regions to value positions
for (i = regionMap.length; i--;) {
if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {
return regionMap[i][2];
}
}
return undefined;
},
getCurrentRegionFields: function () {
var currentRegion = this.currentRegion;
return {
isNull: this.yvalues[currentRegion] === null,
x: this.xvalues[currentRegion],
y: this.yvalues[currentRegion],
color: this.options.get('lineColor'),
fillColor: this.options.get('fillColor'),
offset: currentRegion
};
},
renderHighlight: function () {
var currentRegion = this.currentRegion,
target = this.target,
vertex = this.vertices[currentRegion],
options = this.options,
spotRadius = options.get('spotRadius'),
highlightSpotColor = options.get('highlightSpotColor'),
highlightLineColor = options.get('highlightLineColor'),
highlightSpot, highlightLine;
if (!vertex) {
return;
}
if (spotRadius && highlightSpotColor) {
highlightSpot = target.drawCircle(vertex[0], vertex[1],
spotRadius, undefined, highlightSpotColor);
this.highlightSpotId = highlightSpot.id;
target.insertAfterShape(this.lastShapeId, highlightSpot);
}
if (highlightLineColor) {
highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],
this.canvasTop + this.canvasHeight, highlightLineColor);
this.highlightLineId = highlightLine.id;
target.insertAfterShape(this.lastShapeId, highlightLine);
}
},
removeHighlight: function () {
var target = this.target;
if (this.highlightSpotId) {
target.removeShapeId(this.highlightSpotId);
this.highlightSpotId = null;
}
if (this.highlightLineId) {
target.removeShapeId(this.highlightLineId);
this.highlightLineId = null;
}
},
scanValues: function () {
var values = this.values,
valcount = values.length,
xvalues = this.xvalues,
yvalues = this.yvalues,
yminmax = this.yminmax,
i, val, isStr, isArray, sp;
for (i = 0; i < valcount; i++) {
val = values[i];
isStr = typeof(values[i]) === 'string';
isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;
sp = isStr && values[i].split(':');
if (isStr && sp.length === 2) { // x:y
xvalues.push(Number(sp[0]));
yvalues.push(Number(sp[1]));
yminmax.push(Number(sp[1]));
} else if (isArray) {
xvalues.push(val[0]);
yvalues.push(val[1]);
yminmax.push(val[1]);
} else {
xvalues.push(i);
if (values[i] === null || values[i] === 'null') {
yvalues.push(null);
} else {
yvalues.push(Number(val));
yminmax.push(Number(val));
}
}
}
if (this.options.get('xvalues')) {
xvalues = this.options.get('xvalues');
}
this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);
this.miny = this.minyorg = Math.min.apply(Math, yminmax);
this.maxx = Math.max.apply(Math, xvalues);
this.minx = Math.min.apply(Math, xvalues);
this.xvalues = xvalues;
this.yvalues = yvalues;
this.yminmax = yminmax;
},
processRangeOptions: function () {
var options = this.options,
normalRangeMin = options.get('normalRangeMin'),
normalRangeMax = options.get('normalRangeMax');
if (normalRangeMin !== undefined) {
if (normalRangeMin < this.miny) {
this.miny = normalRangeMin;
}
if (normalRangeMax > this.maxy) {
this.maxy = normalRangeMax;
}
}
if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {
this.miny = options.get('chartRangeMin');
}
if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {
this.maxy = options.get('chartRangeMax');
}
if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {
this.minx = options.get('chartRangeMinX');
}
if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {
this.maxx = options.get('chartRangeMaxX');
}
},
drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {
var normalRangeMin = this.options.get('normalRangeMin'),
normalRangeMax = this.options.get('normalRangeMax'),
ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),
height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);
this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();
},
render: function () {
var options = this.options,
target = this.target,
canvasWidth = this.canvasWidth,
canvasHeight = this.canvasHeight,
vertices = this.vertices,
spotRadius = options.get('spotRadius'),
regionMap = this.regionMap,
rangex, rangey, yvallast,
canvasTop, canvasLeft,
vertex, path, paths, x, y, xnext, xpos, xposnext,
last, next, yvalcount, lineShapes, fillShapes, plen,
valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;
if (!line._super.render.call(this)) {
return;
}
this.scanValues();
this.processRangeOptions();
xvalues = this.xvalues;
yvalues = this.yvalues;
if (!this.yminmax.length || this.yvalues.length < 2) {
// empty or all null valuess
return;
}
canvasTop = canvasLeft = 0;
rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;
rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;
yvallast = this.yvalues.length - 1;
if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {
spotRadius = 0;
}
if (spotRadius) {
// adjust the canvas size as required so that spots will fit
hlSpotsEnabled = options.get('highlightSpotColor') && !options.get('disableInteraction');
if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {
canvasHeight -= Math.ceil(spotRadius);
}
if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {
canvasHeight -= Math.ceil(spotRadius);
canvasTop += Math.ceil(spotRadius);
}
if (hlSpotsEnabled ||
((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {
canvasLeft += Math.ceil(spotRadius);
canvasWidth -= Math.ceil(spotRadius);
}
if (hlSpotsEnabled || options.get('spotColor') ||
(options.get('minSpotColor') || options.get('maxSpotColor') &&
(yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {
canvasWidth -= Math.ceil(spotRadius);
}
}
canvasHeight--;
if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {
this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
}
path = [];
paths = [path];
last = next = null;
yvalcount = yvalues.length;
for (i = 0; i < yvalcount; i++) {
x = xvalues[i];
xnext = xvalues[i + 1];
y = yvalues[i];
xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));
xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;
next = xpos + ((xposnext - xpos) / 2);
regionMap[i] = [last || 0, next, i];
last = next;
if (y === null) {
if (i) {
if (yvalues[i - 1] !== null) {
path = [];
paths.push(path);
}
vertices.push(null);
}
} else {
if (y < this.miny) {
y = this.miny;
}
if (y > this.maxy) {
y = this.maxy;
}
if (!path.length) {
// previous value was null
path.push([xpos, canvasTop + canvasHeight]);
}
vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];
path.push(vertex);
vertices.push(vertex);
}
}
lineShapes = [];
fillShapes = [];
plen = paths.length;
for (i = 0; i < plen; i++) {
path = paths[i];
if (path.length) {
if (options.get('fillColor')) {
path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);
fillShapes.push(path.slice(0));
path.pop();
}
// if there's only a single point in this path, then we want to display it
// as a vertical line which means we keep path[0] as is
if (path.length > 2) {
// else we want the first value
path[0] = [path[0][0], path[1][1]];
}
lineShapes.push(path);
}
}
// draw the fill first, then optionally the normal range, then the line on top of that
plen = fillShapes.length;
for (i = 0; i < plen; i++) {
target.drawShape(fillShapes[i],
options.get('fillColor'), options.get('fillColor')).append();
}
if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {
this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);
}
plen = lineShapes.length;
for (i = 0; i < plen; i++) {
target.drawShape(lineShapes[i], options.get('lineColor'), undefined,
options.get('lineWidth')).append();
}
if (spotRadius && options.get('valueSpots')) {
valueSpots = options.get('valueSpots');
if (valueSpots.get === undefined) {
valueSpots = new RangeMap(valueSpots);
}
for (i = 0; i < yvalcount; i++) {
color = valueSpots.get(yvalues[i]);
if (color) {
target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),
canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),
spotRadius, undefined,
color).append();
}
}
}
if (spotRadius && options.get('spotColor') && yvalues[yvallast] !== null) {
target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),
canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),
spotRadius, undefined,
options.get('spotColor')).append();
}
if (this.maxy !== this.minyorg) {
if (spotRadius && options.get('minSpotColor')) {
x = xvalues[$.inArray(this.minyorg, yvalues)];
target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),
spotRadius, undefined,
options.get('minSpotColor')).append();
}
if (spotRadius && options.get('maxSpotColor')) {
x = xvalues[$.inArray(this.maxyorg, yvalues)];
target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),
canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),
spotRadius, undefined,
options.get('maxSpotColor')).append();
}
}
this.lastShapeId = target.getLastShapeId();
this.canvasTop = canvasTop;
target.render();
}
});
@@ -0,0 +1,112 @@
/**
* Pie charts
*/
$.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {
type: 'pie',
init: function (el, values, options, width, height) {
var total = 0, i;
pie._super.init.call(this, el, values, options, width, height);
this.shapes = {}; // map shape ids to value offsets
this.valueShapes = {}; // maps value offsets to shape ids
this.values = values = $.map(values, Number);
if (options.get('width') === 'auto') {
this.width = this.height;
}
if (values.length > 0) {
for (i = values.length; i--;) {
total += values[i];
}
}
this.total = total;
this.initTarget();
this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);
},
getRegion: function (el, x, y) {
var shapeid = this.target.getShapeAt(el, x, y);
return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;
},
getCurrentRegionFields: function () {
var currentRegion = this.currentRegion;
return {
isNull: this.values[currentRegion] === undefined,
value: this.values[currentRegion],
percent: this.values[currentRegion] / this.total * 100,
color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],
offset: currentRegion
};
},
changeHighlight: function (highlight) {
var currentRegion = this.currentRegion,
newslice = this.renderSlice(currentRegion, highlight),
shapeid = this.valueShapes[currentRegion];
delete this.shapes[shapeid];
this.target.replaceWithShape(shapeid, newslice);
this.valueShapes[currentRegion] = newslice.id;
this.shapes[newslice.id] = currentRegion;
},
renderSlice: function (valuenum, highlight) {
var target = this.target,
options = this.options,
radius = this.radius,
borderWidth = options.get('borderWidth'),
offset = options.get('offset'),
circle = 2 * Math.PI,
values = this.values,
total = this.total,
next = offset ? (2*Math.PI)*(offset/360) : 0,
start, end, i, vlen, color;
vlen = values.length;
for (i = 0; i < vlen; i++) {
start = next;
end = next;
if (total > 0) { // avoid divide by zero
end = next + (circle * (values[i] / total));
}
if (valuenum === i) {
color = options.get('sliceColors')[i % options.get('sliceColors').length];
if (highlight) {
color = this.calcHighlightColor(color, options);
}
return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);
}
next = end;
}
},
render: function () {
var target = this.target,
values = this.values,
options = this.options,
radius = this.radius,
borderWidth = options.get('borderWidth'),
shape, i;
if (!pie._super.render.call(this)) {
return;
}
if (borderWidth) {
target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),
options.get('borderColor'), undefined, borderWidth).append();
}
for (i = values.length; i--;) {
if (values[i]) { // don't render zero values
shape = this.renderSlice(i).append();
this.valueShapes[i] = shape.id; // store just the shapeid
this.shapes[shape.id] = i;
}
}
target.render();
}
});
@@ -0,0 +1,98 @@
/**
* Tristate charts
*/
$.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {
type: 'tristate',
init: function (el, values, options, width, height) {
var barWidth = parseInt(options.get('barWidth'), 10),
barSpacing = parseInt(options.get('barSpacing'), 10);
tristate._super.init.call(this, el, values, options, width, height);
this.regionShapes = {};
this.barWidth = barWidth;
this.barSpacing = barSpacing;
this.totalBarWidth = barWidth + barSpacing;
this.values = $.map(values, Number);
this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);
if ($.isArray(options.get('colorMap'))) {
this.colorMapByIndex = options.get('colorMap');
this.colorMapByValue = null;
} else {
this.colorMapByIndex = null;
this.colorMapByValue = options.get('colorMap');
if (this.colorMapByValue && this.colorMapByValue.get === undefined) {
this.colorMapByValue = new RangeMap(this.colorMapByValue);
}
}
this.initTarget();
},
getRegion: function (el, x, y) {
return Math.floor(x / this.totalBarWidth);
},
getCurrentRegionFields: function () {
var currentRegion = this.currentRegion;
return {
isNull: this.values[currentRegion] === undefined,
value: this.values[currentRegion],
color: this.calcColor(this.values[currentRegion], currentRegion),
offset: currentRegion
};
},
calcColor: function (value, valuenum) {
var values = this.values,
options = this.options,
colorMapByIndex = this.colorMapByIndex,
colorMapByValue = this.colorMapByValue,
color, newColor;
if (colorMapByValue && (newColor = colorMapByValue.get(value))) {
color = newColor;
} else if (colorMapByIndex && colorMapByIndex.length > valuenum) {
color = colorMapByIndex[valuenum];
} else if (values[valuenum] < 0) {
color = options.get('negBarColor');
} else if (values[valuenum] > 0) {
color = options.get('posBarColor');
} else {
color = options.get('zeroBarColor');
}
return color;
},
renderRegion: function (valuenum, highlight) {
var values = this.values,
options = this.options,
target = this.target,
canvasHeight, height, halfHeight,
x, y, color;
canvasHeight = target.pixelHeight;
halfHeight = Math.round(canvasHeight / 2);
x = valuenum * this.totalBarWidth;
if (values[valuenum] < 0) {
y = halfHeight;
height = halfHeight - 1;
} else if (values[valuenum] > 0) {
y = 0;
height = halfHeight - 1;
} else {
y = halfHeight - 1;
height = 2;
}
color = this.calcColor(values[valuenum], valuenum);
if (color === null) {
return;
}
if (highlight) {
color = this.calcHighlightColor(color, options);
}
return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);
}
});
@@ -0,0 +1,156 @@
/**
* Default configuration settings
*/
getDefaults = function () {
return {
// Settings common to most/all chart types
common: {
type: 'line',
lineColor: '#00f',
fillColor: '#cdf',
defaultPixelsPerValue: 3,
width: 'auto',
height: 'auto',
composite: false,
tagValuesAttribute: 'values',
tagOptionsPrefix: 'spark',
enableTagOptions: false,
enableHighlight: true,
highlightLighten: 1.4,
tooltipSkipNull: true,
tooltipPrefix: '',
tooltipSuffix: '',
disableHiddenCheck: false,
numberFormatter: false,
numberDigitGroupCount: 3,
numberDigitGroupSep: ',',
numberDecimalMark: '.',
disableTooltips: false,
disableInteraction: false
},
// Defaults for line charts
line: {
spotColor: '#f80',
highlightSpotColor: '#5f5',
highlightLineColor: '#f22',
spotRadius: 1.5,
minSpotColor: '#f80',
maxSpotColor: '#f80',
lineWidth: 1,
normalRangeMin: undefined,
normalRangeMax: undefined,
normalRangeColor: '#ccc',
drawNormalOnTop: false,
chartRangeMin: undefined,
chartRangeMax: undefined,
chartRangeMinX: undefined,
chartRangeMaxX: undefined,
tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{prefix}}{{y}}{{suffix}}')
},
// Defaults for bar charts
bar: {
barColor: '#3366cc',
negBarColor: '#f44',
stackedBarColor: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
'#dd4477', '#0099c6', '#990099'],
zeroColor: undefined,
nullColor: undefined,
zeroAxis: true,
barWidth: 4,
barSpacing: 1,
chartRangeMax: undefined,
chartRangeMin: undefined,
chartRangeClip: false,
colorMap: undefined,
tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{prefix}}{{value}}{{suffix}}')
},
// Defaults for tristate charts
tristate: {
barWidth: 4,
barSpacing: 1,
posBarColor: '#6f6',
negBarColor: '#f44',
zeroBarColor: '#999',
colorMap: {},
tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{value:map}}'),
tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }
},
// Defaults for discrete charts
discrete: {
lineHeight: 'auto',
thresholdColor: undefined,
thresholdValue: 0,
chartRangeMax: undefined,
chartRangeMin: undefined,
chartRangeClip: false,
tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')
},
// Defaults for bullet charts
bullet: {
targetColor: '#f33',
targetWidth: 3, // width of the target bar in pixels
performanceColor: '#33f',
rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],
base: undefined, // set this to a number to change the base start number
tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),
tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }
},
// Defaults for pie charts
pie: {
offset: 0,
sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',
'#dd4477', '#0099c6', '#990099'],
borderWidth: 0,
borderColor: '#000',
tooltipFormat: new SPFormat('<span style="color: {{color}}">&#9679;</span> {{value}} ({{percent.1}}%)')
},
// Defaults for box plots
box: {
raw: false,
boxLineColor: '#000',
boxFillColor: '#cdf',
whiskerColor: '#000',
outlierLineColor: '#333',
outlierFillColor: '#fff',
medianColor: '#f00',
showOutliers: true,
outlierIQR: 1.5,
spotRadius: 1.5,
target: undefined,
targetColor: '#4a2',
chartRangeMax: undefined,
chartRangeMin: undefined,
tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),
tooltipFormatFieldlistKey: 'field',
tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',
uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',
lw: 'Left Whisker', rw: 'Right Whisker'} }
}
};
};
// You can have tooltips use a css class other than jqstooltip by specifying tooltipClassname
defaultStyles = '.jqstooltip { ' +
'position: absolute;' +
'left: 0px;' +
'top: 0px;' +
'visibility: hidden;' +
'background: rgb(0, 0, 0) transparent;' +
'background-color: rgba(0,0,0,0.6);' +
'filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);' +
'-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)";' +
'color: white;' +
'font: 10px arial, san serif;' +
'text-align: left;' +
'white-space: nowrap;' +
'padding: 5px;' +
'border: 1px solid white;' +
'box-sizing: content-box;' +
'z-index: 10000;' +
'}' +
'.jqsfield { ' +
'color: white;' +
'font: 10px arial, san serif;' +
'text-align: left;' +
'}';
@@ -0,0 +1 @@
}))}(document, Math));
@@ -0,0 +1,222 @@
/**
*
* jquery.sparkline.js
*
* v@VERSION@
* (c) Splunk, Inc
* Contact: Gareth Watts (gareth@splunk.com)
* http://omnipotent.net/jquery.sparkline/
*
* Generates inline sparkline charts from data supplied either to the method
* or inline in HTML
*
* Compatible with Internet Explorer 6.0+ and modern browsers equipped with the canvas tag
* (Firefox 2.0+, Safari, Opera, etc)
*
* License: New BSD License
*
* Copyright (c) 2012, Splunk Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Splunk Inc nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Usage:
* $(selector).sparkline(values, options)
*
* If values is undefined or set to 'html' then the data values are read from the specified tag:
* <p>Sparkline: <span class="sparkline">1,4,6,6,8,5,3,5</span></p>
* $('.sparkline').sparkline();
* There must be no spaces in the enclosed data set
*
* Otherwise values must be an array of numbers or null values
* <p>Sparkline: <span id="sparkline1">This text replaced if the browser is compatible</span></p>
* $('#sparkline1').sparkline([1,4,6,6,8,5,3,5])
* $('#sparkline2').sparkline([1,4,6,null,null,5,3,5])
*
* Values can also be specified in an HTML comment, or as a values attribute:
* <p>Sparkline: <span class="sparkline"><!--1,4,6,6,8,5,3,5 --></span></p>
* <p>Sparkline: <span class="sparkline" values="1,4,6,6,8,5,3,5"></span></p>
* $('.sparkline').sparkline();
*
* For line charts, x values can also be specified:
* <p>Sparkline: <span class="sparkline">1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5</span></p>
* $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])
*
* By default, options should be passed in as the second argument to the sparkline function:
* $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})
*
* Options can also be set by passing them on the tag itself. This feature is disabled by default though
* as there's a slight performance overhead:
* $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true})
* <p>Sparkline: <span class="sparkline" sparkType="bar" sparkBarColor="red">loading</span></p>
* Prefix all options supplied as tag attribute with "spark" (configurable by setting tagOptionsPrefix)
*
* Supported options:
* lineColor - Color of the line used for the chart
* fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart
* width - Width of the chart - Defaults to 3 times the number of values in pixels
* height - Height of the chart - Defaults to the height of the containing element
* chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied
* chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied
* chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax
* chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied
* chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied
* composite - If true then don't erase any existing chart attached to the tag, but draw
* another chart over the top - Note that width and height are ignored if an
* existing chart is detected.
* tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values'
* enableTagOptions - Whether to check tags for sparkline options
* tagOptionsPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark'
* disableHiddenCheck - If set to true, then the plugin will assume that charts will never be drawn into a
* hidden dom element, avoding a browser reflow
* disableInteraction - If set to true then all mouseover/click interaction behaviour will be disabled,
* making the plugin perform much like it did in 1.x
* disableTooltips - If set to true then tooltips will be disabled - Defaults to false (tooltips enabled)
* disableHighlight - If set to true then highlighting of selected chart elements on mouseover will be disabled
* defaults to false (highlights enabled)
* highlightLighten - Factor to lighten/darken highlighted chart values by - Defaults to 1.4 for a 40% increase
* tooltipContainer - Specify which DOM element the tooltip should be rendered into - defaults to document.body
* tooltipClassname - Optional CSS classname to apply to tooltips - If not specified then a default style will be applied
* tooltipOffsetX - How many pixels away from the mouse pointer to render the tooltip on the X axis
* tooltipOffsetY - How many pixels away from the mouse pointer to render the tooltip on the r axis
* tooltipFormatter - Optional callback that allows you to override the HTML displayed in the tooltip
* callback is given arguments of (sparkline, options, fields)
* tooltipChartTitle - If specified then the tooltip uses the string specified by this setting as a title
* tooltipFormat - A format string or SPFormat object (or an array thereof for multiple entries)
* to control the format of the tooltip
* tooltipPrefix - A string to prepend to each field displayed in a tooltip
* tooltipSuffix - A string to append to each field displayed in a tooltip
* tooltipSkipNull - If true then null values will not have a tooltip displayed (defaults to true)
* tooltipValueLookups - An object or range map to map field values to tooltip strings
* (eg. to map -1 to "Lost", 0 to "Draw", and 1 to "Win")
* numberFormatter - Optional callback for formatting numbers in tooltips
* numberDigitGroupSep - Character to use for group separator in numbers "1,234" - Defaults to ","
* numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to "."
* numberDigitGroupCount - Number of digits between group separator - Defaults to 3
*
* There are 7 types of sparkline, selected by supplying a "type" option of 'line' (default),
* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'
* line - Line chart. Options:
* spotColor - Set to '' to not end each line in a circular spot
* minSpotColor - If set, color of spot at minimum value
* maxSpotColor - If set, color of spot at maximum value
* spotRadius - Radius in pixels
* lineWidth - Width of line in pixels
* normalRangeMin
* normalRangeMax - If set draws a filled horizontal bar between these two values marking the "normal"
* or expected range of values
* normalRangeColor - Color to use for the above bar
* drawNormalOnTop - Draw the normal range above the chart fill color if true
* defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart
* highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable
* highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable
* valueSpots - Specify which points to draw spots on, and in which color. Accepts a range map
*
* bar - Bar chart. Options:
* barColor - Color of bars for postive values
* negBarColor - Color of bars for negative values
* zeroColor - Color of bars with zero values
* nullColor - Color of bars with null values - Defaults to omitting the bar entirely
* barWidth - Width of bars in pixels
* colorMap - Optional mappnig of values to colors to override the *BarColor values above
* can be an Array of values to control the color of individual bars or a range map
* to specify colors for individual ranges of values
* barSpacing - Gap between bars in pixels
* zeroAxis - Centers the y-axis around zero if true
*
* tristate - Charts values of win (>0), lose (<0) or draw (=0)
* posBarColor - Color of win values
* negBarColor - Color of lose values
* zeroBarColor - Color of draw values
* barWidth - Width of bars in pixels
* barSpacing - Gap between bars in pixels
* colorMap - Optional mappnig of values to colors to override the *BarColor values above
* can be an Array of values to control the color of individual bars or a range map
* to specify colors for individual ranges of values
*
* discrete - Options:
* lineHeight - Height of each line in pixels - Defaults to 30% of the graph height
* thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor
* thresholdColor
*
* bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...
* options:
* targetColor - The color of the vertical target marker
* targetWidth - The width of the target marker in pixels
* performanceColor - The color of the performance measure horizontal bar
* rangeColors - Colors to use for each qualitative range background color
*
* pie - Pie chart. Options:
* sliceColors - An array of colors to use for pie slices
* offset - Angle in degrees to offset the first slice - Try -90 or +90
* borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)
* borderColor - Color to use for the pie chart border - Defaults to #000
*
* box - Box plot. Options:
* raw - Set to true to supply pre-computed plot points as values
* values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier
* When set to false you can supply any number of values and the box plot will
* be computed for you. Default is false.
* showOutliers - Set to true (default) to display outliers as circles
* outlierIQR - Interquartile range used to determine outliers. Default 1.5
* boxLineColor - Outline color of the box
* boxFillColor - Fill color for the box
* whiskerColor - Line color used for whiskers
* outlierLineColor - Outline color of outlier circles
* outlierFillColor - Fill color of the outlier circles
* spotRadius - Radius of outlier circles
* medianColor - Line color of the median line
* target - Draw a target cross hair at the supplied value (default undefined)
*
*
*
* Examples:
* $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });
* $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });
* $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):
* $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });
* $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });
* $('#pie').sparkline([1,1,2], { type:'pie' });
*/
/*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */
(function(document, Math, undefined) { // performance/minified-size optimization
(function(factory) {
if(typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (jQuery && !jQuery.fn.sparkline) {
factory(jQuery);
}
}
(function($) {
'use strict';
var UNSET_OPTION = {},
getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,
remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,
MouseHandler, Tooltip, barHighlightMixin,
line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,
VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;
@@ -0,0 +1,247 @@
MouseHandler = createClass({
init: function (el, options) {
var $el = $(el);
this.$el = $el;
this.options = options;
this.currentPageX = 0;
this.currentPageY = 0;
this.el = el;
this.splist = [];
this.tooltip = null;
this.over = false;
this.displayTooltips = !options.get('disableTooltips');
this.highlightEnabled = !options.get('disableHighlight');
},
registerSparkline: function (sp) {
this.splist.push(sp);
if (this.over) {
this.updateDisplay();
}
},
registerCanvas: function (canvas) {
var $canvas = $(canvas.canvas);
this.canvas = canvas;
this.$canvas = $canvas;
$canvas.mouseenter($.proxy(this.mouseenter, this));
$canvas.mouseleave($.proxy(this.mouseleave, this));
$canvas.click($.proxy(this.mouseclick, this));
},
reset: function (removeTooltip) {
this.splist = [];
if (this.tooltip && removeTooltip) {
this.tooltip.remove();
this.tooltip = undefined;
}
},
mouseclick: function (e) {
var clickEvent = $.Event('sparklineClick');
clickEvent.originalEvent = e;
clickEvent.sparklines = this.splist;
this.$el.trigger(clickEvent);
},
mouseenter: function (e) {
$(document.body).unbind('mousemove.jqs');
$(document.body).bind('mousemove.jqs', $.proxy(this.mousemove, this));
this.over = true;
this.currentPageX = e.pageX;
this.currentPageY = e.pageY;
this.currentEl = e.target;
if (!this.tooltip && this.displayTooltips) {
this.tooltip = new Tooltip(this.options);
this.tooltip.updatePosition(e.pageX, e.pageY);
}
this.updateDisplay();
},
mouseleave: function () {
$(document.body).unbind('mousemove.jqs');
var splist = this.splist,
spcount = splist.length,
needsRefresh = false,
sp, i;
this.over = false;
this.currentEl = null;
if (this.tooltip) {
this.tooltip.remove();
this.tooltip = null;
}
for (i = 0; i < spcount; i++) {
sp = splist[i];
if (sp.clearRegionHighlight()) {
needsRefresh = true;
}
}
if (needsRefresh) {
this.canvas.render();
}
},
mousemove: function (e) {
this.currentPageX = e.pageX;
this.currentPageY = e.pageY;
this.currentEl = e.target;
if (this.tooltip) {
this.tooltip.updatePosition(e.pageX, e.pageY);
}
this.updateDisplay();
},
updateDisplay: function () {
var splist = this.splist,
spcount = splist.length,
needsRefresh = false,
offset = this.$canvas.offset(),
localX = this.currentPageX - offset.left,
localY = this.currentPageY - offset.top,
tooltiphtml, sp, i, result, changeEvent;
if (!this.over) {
return;
}
for (i = 0; i < spcount; i++) {
sp = splist[i];
result = sp.setRegionHighlight(this.currentEl, localX, localY);
if (result) {
needsRefresh = true;
}
}
if (needsRefresh) {
changeEvent = $.Event('sparklineRegionChange');
changeEvent.sparklines = this.splist;
this.$el.trigger(changeEvent);
if (this.tooltip) {
tooltiphtml = '';
for (i = 0; i < spcount; i++) {
sp = splist[i];
tooltiphtml += sp.getCurrentRegionTooltip();
}
this.tooltip.setContent(tooltiphtml);
}
if (!this.disableHighlight) {
this.canvas.render();
}
}
if (result === null) {
this.mouseleave();
}
}
});
Tooltip = createClass({
sizeStyle: 'position: static !important;' +
'display: block !important;' +
'visibility: hidden !important;' +
'float: left !important;',
init: function (options) {
var tooltipClassname = options.get('tooltipClassname', 'jqstooltip'),
sizetipStyle = this.sizeStyle,
offset;
this.container = options.get('tooltipContainer') || document.body;
this.tooltipOffsetX = options.get('tooltipOffsetX', 10);
this.tooltipOffsetY = options.get('tooltipOffsetY', 12);
// remove any previous lingering tooltip
$('#jqssizetip').remove();
$('#jqstooltip').remove();
this.sizetip = $('<div/>', {
id: 'jqssizetip',
style: sizetipStyle,
'class': tooltipClassname
});
this.tooltip = $('<div/>', {
id: 'jqstooltip',
'class': tooltipClassname
}).appendTo(this.container);
// account for the container's location
offset = this.tooltip.offset();
this.offsetLeft = offset.left;
this.offsetTop = offset.top;
this.hidden = true;
$(window).unbind('resize.jqs scroll.jqs');
$(window).bind('resize.jqs scroll.jqs', $.proxy(this.updateWindowDims, this));
this.updateWindowDims();
},
updateWindowDims: function () {
this.scrollTop = $(window).scrollTop();
this.scrollLeft = $(window).scrollLeft();
this.scrollRight = this.scrollLeft + $(window).width();
this.updatePosition();
},
getSize: function (content) {
this.sizetip.html(content).appendTo(this.container);
this.width = this.sizetip.width() + 1;
this.height = this.sizetip.height();
this.sizetip.remove();
},
setContent: function (content) {
if (!content) {
this.tooltip.css('visibility', 'hidden');
this.hidden = true;
return;
}
this.getSize(content);
this.tooltip.html(content)
.css({
'width': this.width,
'height': this.height,
'visibility': 'visible'
});
if (this.hidden) {
this.hidden = false;
this.updatePosition();
}
},
updatePosition: function (x, y) {
if (x === undefined) {
if (this.mousex === undefined) {
return;
}
x = this.mousex - this.offsetLeft;
y = this.mousey - this.offsetTop;
} else {
this.mousex = x = x - this.offsetLeft;
this.mousey = y = y - this.offsetTop;
}
if (!this.height || !this.width || this.hidden) {
return;
}
y -= this.height + this.tooltipOffsetY;
x += this.tooltipOffsetX;
if (y < this.scrollTop) {
y = this.scrollTop;
}
if (x < this.scrollLeft) {
x = this.scrollLeft;
} else if (x + this.width > this.scrollRight) {
x = this.scrollRight - this.width;
}
this.tooltip.css({
'left': x,
'top': y
});
},
remove: function () {
this.tooltip.remove();
this.sizetip.remove();
this.sizetip = this.tooltip = undefined;
$(window).unbind('resize.jqs scroll.jqs');
}
});
@@ -0,0 +1,39 @@
$.RangeMapClass = RangeMap = createClass({
init: function (map) {
var key, range, rangelist = [];
for (key in map) {
if (map.hasOwnProperty(key) && typeof key === 'string' && key.indexOf(':') > -1) {
range = key.split(':');
range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);
range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);
range[2] = map[key];
rangelist.push(range);
}
}
this.map = map;
this.rangelist = rangelist || false;
},
get: function (value) {
var rangelist = this.rangelist,
i, range, result;
if ((result = this.map[value]) !== undefined) {
return result;
}
if (rangelist) {
for (i = rangelist.length; i--;) {
range = rangelist[i];
if (range[0] <= value && range[1] >= value) {
return range[2];
}
}
}
return undefined;
}
});
// Convenience function
$.range_map = function(map) {
return new RangeMap(map);
};
@@ -0,0 +1,55 @@
// Provide a cross-browser interface to a few simple drawing primitives
$.fn.simpledraw = function (width, height, useExisting, interact) {
var target, mhandler;
if (useExisting && (target = this.data('_jqs_vcanvas'))) {
return target;
}
if ($.fn.sparkline.canvas === false) {
// We've already determined that neither Canvas nor VML are available
return false;
} else if ($.fn.sparkline.canvas === undefined) {
// No function defined yet -- need to see if we support Canvas or VML
var el = document.createElement('canvas');
if (!!(el.getContext && el.getContext('2d'))) {
// Canvas is available
$.fn.sparkline.canvas = function(width, height, target, interact) {
return new VCanvas_canvas(width, height, target, interact);
};
} else if (document.namespaces && !document.namespaces.v) {
// VML is available
document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');
$.fn.sparkline.canvas = function(width, height, target, interact) {
return new VCanvas_vml(width, height, target);
};
} else {
// Neither Canvas nor VML are available
$.fn.sparkline.canvas = false;
return false;
}
}
if (width === undefined) {
width = $(this).innerWidth();
}
if (height === undefined) {
height = $(this).innerHeight();
}
target = $.fn.sparkline.canvas(width, height, this, interact);
mhandler = $(this).data('_jqs_mhandler');
if (mhandler) {
mhandler.registerCanvas(target);
}
return target;
};
$.fn.cleardraw = function () {
var target = this.data('_jqs_vcanvas');
if (target) {
target.reset();
}
};
@@ -0,0 +1,224 @@
/**
* Utilities
*/
createClass = function (/* [baseclass, [mixin, ...]], definition */) {
var Class, args;
Class = function () {
this.init.apply(this, arguments);
};
if (arguments.length > 1) {
if (arguments[0]) {
Class.prototype = $.extend(new arguments[0](), arguments[arguments.length - 1]);
Class._super = arguments[0].prototype;
} else {
Class.prototype = arguments[arguments.length - 1];
}
if (arguments.length > 2) {
args = Array.prototype.slice.call(arguments, 1, -1);
args.unshift(Class.prototype);
$.extend.apply($, args);
}
} else {
Class.prototype = arguments[0];
}
Class.prototype.cls = Class;
return Class;
};
/**
* Wraps a format string for tooltips
* {{x}}
* {{x.2}
* {{x:months}}
*/
$.SPFormatClass = SPFormat = createClass({
fre: /\{\{([\w.]+?)(:(.+?))?\}\}/g,
precre: /(\w+)\.(\d+)/,
init: function (format, fclass) {
this.format = format;
this.fclass = fclass;
},
render: function (fieldset, lookups, options) {
var self = this,
fields = fieldset,
match, token, lookupkey, fieldvalue, prec;
return this.format.replace(this.fre, function () {
var lookup;
token = arguments[1];
lookupkey = arguments[3];
match = self.precre.exec(token);
if (match) {
prec = match[2];
token = match[1];
} else {
prec = false;
}
fieldvalue = fields[token];
if (fieldvalue === undefined) {
return '';
}
if (lookupkey && lookups && lookups[lookupkey]) {
lookup = lookups[lookupkey];
if (lookup.get) { // RangeMap
return lookups[lookupkey].get(fieldvalue) || fieldvalue;
} else {
return lookups[lookupkey][fieldvalue] || fieldvalue;
}
}
if (isNumber(fieldvalue)) {
if (options.get('numberFormatter')) {
fieldvalue = options.get('numberFormatter')(fieldvalue);
} else {
fieldvalue = formatNumber(fieldvalue, prec,
options.get('numberDigitGroupCount'),
options.get('numberDigitGroupSep'),
options.get('numberDecimalMark'));
}
}
return fieldvalue;
});
}
});
// convience method to avoid needing the new operator
$.spformat = function(format, fclass) {
return new SPFormat(format, fclass);
};
clipval = function (val, min, max) {
if (val < min) {
return min;
}
if (val > max) {
return max;
}
return val;
};
quartile = function (values, q) {
var vl;
if (q === 2) {
vl = Math.floor(values.length / 2);
return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;
} else {
if (values.length % 2 ) { // odd
vl = (values.length * q + q) / 4;
return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
} else { //even
vl = (values.length * q + 2) / 4;
return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];
}
}
};
normalizeValue = function (val) {
var nf;
switch (val) {
case 'undefined':
val = undefined;
break;
case 'null':
val = null;
break;
case 'true':
val = true;
break;
case 'false':
val = false;
break;
default:
nf = parseFloat(val);
if (val == nf) {
val = nf;
}
}
return val;
};
normalizeValues = function (vals) {
var i, result = [];
for (i = vals.length; i--;) {
result[i] = normalizeValue(vals[i]);
}
return result;
};
remove = function (vals, filter) {
var i, vl, result = [];
for (i = 0, vl = vals.length; i < vl; i++) {
if (vals[i] !== filter) {
result.push(vals[i]);
}
}
return result;
};
isNumber = function (num) {
return !isNaN(parseFloat(num)) && isFinite(num);
};
formatNumber = function (num, prec, groupsize, groupsep, decsep) {
var p, i;
num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split('');
p = (p = $.inArray('.', num)) < 0 ? num.length : p;
if (p < num.length) {
num[p] = decsep;
}
for (i = p - groupsize; i > 0; i -= groupsize) {
num.splice(i, 0, groupsep);
}
return num.join('');
};
// determine if all values of an array match a value
// returns true if the array is empty
all = function (val, arr, ignoreNull) {
var i;
for (i = arr.length; i--; ) {
if (ignoreNull && arr[i] === null) continue;
if (arr[i] !== val) {
return false;
}
}
return true;
};
// sums the numeric values in an array, ignoring other values
sum = function (vals) {
var total = 0, i;
for (i = vals.length; i--;) {
total += typeof vals[i] === 'number' ? vals[i] : 0;
}
return total;
};
ensureArray = function (val) {
return $.isArray(val) ? val : [val];
};
// http://paulirish.com/2008/bookmarklet-inject-new-css-rules/
addCSS = function(css) {
var tag, iefail;
if (document.createStyleSheet) {
try {
document.createStyleSheet().cssText = css;
return;
} catch (e) {
// IE <= 9 maxes out at 31 stylesheets; inject into page instead.
iefail = true;
}
}
tag = document.createElement('style');
tag.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(tag);
if (iefail) {
document.styleSheets[document.styleSheets.length - 1].cssText = css;
} else {
tag[(typeof document.body.style.WebkitAppearance == 'string') /* webkit only */ ? 'innerText' : 'innerHTML'] = css;
}
};
@@ -0,0 +1,147 @@
// Setup a very simple "virtual canvas" to make drawing the few shapes we need easier
// This is accessible as $(foo).simpledraw()
VShape = createClass({
init: function (target, id, type, args) {
this.target = target;
this.id = id;
this.type = type;
this.args = args;
},
append: function () {
this.target.appendShape(this);
return this;
}
});
VCanvas_base = createClass({
_pxregex: /(\d+)(px)?\s*$/i,
init: function (width, height, target) {
if (!width) {
return;
}
this.width = width;
this.height = height;
this.target = target;
this.lastShapeId = null;
if (target[0]) {
target = target[0];
}
$.data(target, '_jqs_vcanvas', this);
},
drawLine: function (x1, y1, x2, y2, lineColor, lineWidth) {
return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);
},
drawShape: function (path, lineColor, fillColor, lineWidth) {
return this._genShape('Shape', [path, lineColor, fillColor, lineWidth]);
},
drawCircle: function (x, y, radius, lineColor, fillColor, lineWidth) {
return this._genShape('Circle', [x, y, radius, lineColor, fillColor, lineWidth]);
},
drawPieSlice: function (x, y, radius, startAngle, endAngle, lineColor, fillColor) {
return this._genShape('PieSlice', [x, y, radius, startAngle, endAngle, lineColor, fillColor]);
},
drawRect: function (x, y, width, height, lineColor, fillColor) {
return this._genShape('Rect', [x, y, width, height, lineColor, fillColor]);
},
getElement: function () {
return this.canvas;
},
/**
* Return the most recently inserted shape id
*/
getLastShapeId: function () {
return this.lastShapeId;
},
/**
* Clear and reset the canvas
*/
reset: function () {
alert('reset not implemented');
},
_insert: function (el, target) {
$(target).html(el);
},
/**
* Calculate the pixel dimensions of the canvas
*/
_calculatePixelDims: function (width, height, canvas) {
// XXX This should probably be a configurable option
var match;
match = this._pxregex.exec(height);
if (match) {
this.pixelHeight = match[1];
} else {
this.pixelHeight = $(canvas).height();
}
match = this._pxregex.exec(width);
if (match) {
this.pixelWidth = match[1];
} else {
this.pixelWidth = $(canvas).width();
}
},
/**
* Generate a shape object and id for later rendering
*/
_genShape: function (shapetype, shapeargs) {
var id = shapeCount++;
shapeargs.unshift(id);
return new VShape(this, id, shapetype, shapeargs);
},
/**
* Add a shape to the end of the render queue
*/
appendShape: function (shape) {
alert('appendShape not implemented');
},
/**
* Replace one shape with another
*/
replaceWithShape: function (shapeid, shape) {
alert('replaceWithShape not implemented');
},
/**
* Insert one shape after another in the render queue
*/
insertAfterShape: function (shapeid, shape) {
alert('insertAfterShape not implemented');
},
/**
* Remove a shape from the queue
*/
removeShapeId: function (shapeid) {
alert('removeShapeId not implemented');
},
/**
* Find a shape at the specified x/y co-ordinates
*/
getShapeAt: function (el, x, y) {
alert('getShapeAt not implemented');
},
/**
* Render all queued shapes onto the canvas
*/
render: function () {
alert('render not implemented');
}
});
@@ -0,0 +1,193 @@
VCanvas_canvas = createClass(VCanvas_base, {
init: function (width, height, target, interact) {
VCanvas_canvas._super.init.call(this, width, height, target);
this.canvas = document.createElement('canvas');
if (target[0]) {
target = target[0];
}
$.data(target, '_jqs_vcanvas', this);
$(this.canvas).css({ display: 'inline-block', width: width, height: height, verticalAlign: 'top' });
this._insert(this.canvas, target);
this._calculatePixelDims(width, height, this.canvas);
this.canvas.width = this.pixelWidth;
this.canvas.height = this.pixelHeight;
this.interact = interact;
this.shapes = {};
this.shapeseq = [];
this.currentTargetShapeId = undefined;
$(this.canvas).css({width: this.pixelWidth, height: this.pixelHeight});
},
_getContext: function (lineColor, fillColor, lineWidth) {
var context = this.canvas.getContext('2d');
if (lineColor !== undefined) {
context.strokeStyle = lineColor;
}
context.lineWidth = lineWidth === undefined ? 1 : lineWidth;
if (fillColor !== undefined) {
context.fillStyle = fillColor;
}
return context;
},
reset: function () {
var context = this._getContext();
context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
this.shapes = {};
this.shapeseq = [];
this.currentTargetShapeId = undefined;
},
_drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
var context = this._getContext(lineColor, fillColor, lineWidth),
i, plen;
context.beginPath();
context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);
for (i = 1, plen = path.length; i < plen; i++) {
context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5); // the 0.5 offset gives us crisp pixel-width lines
}
if (lineColor !== undefined) {
context.stroke();
}
if (fillColor !== undefined) {
context.fill();
}
if (this.targetX !== undefined && this.targetY !== undefined &&
context.isPointInPath(this.targetX, this.targetY)) {
this.currentTargetShapeId = shapeid;
}
},
_drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
var context = this._getContext(lineColor, fillColor, lineWidth);
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
if (this.targetX !== undefined && this.targetY !== undefined &&
context.isPointInPath(this.targetX, this.targetY)) {
this.currentTargetShapeId = shapeid;
}
if (lineColor !== undefined) {
context.stroke();
}
if (fillColor !== undefined) {
context.fill();
}
},
_drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
var context = this._getContext(lineColor, fillColor);
context.beginPath();
context.moveTo(x, y);
context.arc(x, y, radius, startAngle, endAngle, false);
context.lineTo(x, y);
context.closePath();
if (lineColor !== undefined) {
context.stroke();
}
if (fillColor) {
context.fill();
}
if (this.targetX !== undefined && this.targetY !== undefined &&
context.isPointInPath(this.targetX, this.targetY)) {
this.currentTargetShapeId = shapeid;
}
},
_drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);
},
appendShape: function (shape) {
this.shapes[shape.id] = shape;
this.shapeseq.push(shape.id);
this.lastShapeId = shape.id;
return shape.id;
},
replaceWithShape: function (shapeid, shape) {
var shapeseq = this.shapeseq,
i;
this.shapes[shape.id] = shape;
for (i = shapeseq.length; i--;) {
if (shapeseq[i] == shapeid) {
shapeseq[i] = shape.id;
}
}
delete this.shapes[shapeid];
},
replaceWithShapes: function (shapeids, shapes) {
var shapeseq = this.shapeseq,
shapemap = {},
sid, i, first;
for (i = shapeids.length; i--;) {
shapemap[shapeids[i]] = true;
}
for (i = shapeseq.length; i--;) {
sid = shapeseq[i];
if (shapemap[sid]) {
shapeseq.splice(i, 1);
delete this.shapes[sid];
first = i;
}
}
for (i = shapes.length; i--;) {
shapeseq.splice(first, 0, shapes[i].id);
this.shapes[shapes[i].id] = shapes[i];
}
},
insertAfterShape: function (shapeid, shape) {
var shapeseq = this.shapeseq,
i;
for (i = shapeseq.length; i--;) {
if (shapeseq[i] === shapeid) {
shapeseq.splice(i + 1, 0, shape.id);
this.shapes[shape.id] = shape;
return;
}
}
},
removeShapeId: function (shapeid) {
var shapeseq = this.shapeseq,
i;
for (i = shapeseq.length; i--;) {
if (shapeseq[i] === shapeid) {
shapeseq.splice(i, 1);
break;
}
}
delete this.shapes[shapeid];
},
getShapeAt: function (el, x, y) {
this.targetX = x;
this.targetY = y;
this.render();
return this.currentTargetShapeId;
},
render: function () {
var shapeseq = this.shapeseq,
shapes = this.shapes,
shapeCount = shapeseq.length,
context = this._getContext(),
shapeid, shape, i;
context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);
for (i = 0; i < shapeCount; i++) {
shapeid = shapeseq[i];
shape = shapes[shapeid];
this['_draw' + shape.type].apply(this, shape.args);
}
if (!this.interact) {
// not interactive so no need to keep the shapes array
this.shapes = {};
this.shapeseq = [];
}
}
});
@@ -0,0 +1,165 @@
VCanvas_vml = createClass(VCanvas_base, {
init: function (width, height, target) {
var groupel;
VCanvas_vml._super.init.call(this, width, height, target);
if (target[0]) {
target = target[0];
}
$.data(target, '_jqs_vcanvas', this);
this.canvas = document.createElement('span');
$(this.canvas).css({ display: 'inline-block', position: 'relative', overflow: 'hidden', width: width, height: height, margin: '0px', padding: '0px', verticalAlign: 'top'});
this._insert(this.canvas, target);
this._calculatePixelDims(width, height, this.canvas);
this.canvas.width = this.pixelWidth;
this.canvas.height = this.pixelHeight;
groupel = '<v:group coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '"' +
' style="position:absolute;top:0;left:0;width:' + this.pixelWidth + 'px;height=' + this.pixelHeight + 'px;"></v:group>';
this.canvas.insertAdjacentHTML('beforeEnd', groupel);
this.group = $(this.canvas).children()[0];
this.rendered = false;
this.prerender = '';
},
_drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {
var vpath = [],
initial, stroke, fill, closed, vel, plen, i;
for (i = 0, plen = path.length; i < plen; i++) {
vpath[i] = '' + (path[i][0]) + ',' + (path[i][1]);
}
initial = vpath.splice(0, 1);
lineWidth = lineWidth === undefined ? 1 : lineWidth;
stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
closed = vpath[0] === vpath[vpath.length - 1] ? 'x ' : '';
vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '" ' +
' id="jqsshape' + shapeid + '" ' +
stroke +
fill +
' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;" ' +
' path="m ' + initial + ' l ' + vpath.join(', ') + ' ' + closed + 'e">' +
' </v:shape>';
return vel;
},
_drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {
var stroke, fill, vel;
x -= radius;
y -= radius;
stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="' + lineWidth + 'px" strokeColor="' + lineColor + '" ';
fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
vel = '<v:oval ' +
' id="jqsshape' + shapeid + '" ' +
stroke +
fill +
' style="position:absolute;top:' + y + 'px; left:' + x + 'px; width:' + (radius * 2) + 'px; height:' + (radius * 2) + 'px"></v:oval>';
return vel;
},
_drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {
var vpath, startx, starty, endx, endy, stroke, fill, vel;
if (startAngle === endAngle) {
return ''; // VML seems to have problem when start angle equals end angle.
}
if ((endAngle - startAngle) === (2 * Math.PI)) {
startAngle = 0.0; // VML seems to have a problem when drawing a full circle that doesn't start 0
endAngle = (2 * Math.PI);
}
startx = x + Math.round(Math.cos(startAngle) * radius);
starty = y + Math.round(Math.sin(startAngle) * radius);
endx = x + Math.round(Math.cos(endAngle) * radius);
endy = y + Math.round(Math.sin(endAngle) * radius);
if (startx === endx && starty === endy) {
if ((endAngle - startAngle) < Math.PI) {
// Prevent very small slices from being mistaken as a whole pie
return '';
}
// essentially going to be the entire circle, so ignore startAngle
startx = endx = x + radius;
starty = endy = y;
}
if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {
return '';
}
vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];
stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="1px" strokeColor="' + lineColor + '" ';
fill = fillColor === undefined ? ' filled="false"' : ' fillColor="' + fillColor + '" filled="true" ';
vel = '<v:shape coordorigin="0 0" coordsize="' + this.pixelWidth + ' ' + this.pixelHeight + '" ' +
' id="jqsshape' + shapeid + '" ' +
stroke +
fill +
' style="position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;" ' +
' path="m ' + x + ',' + y + ' wa ' + vpath.join(', ') + ' x e">' +
' </v:shape>';
return vel;
},
_drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {
return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);
},
reset: function () {
this.group.innerHTML = '';
},
appendShape: function (shape) {
var vel = this['_draw' + shape.type].apply(this, shape.args);
if (this.rendered) {
this.group.insertAdjacentHTML('beforeEnd', vel);
} else {
this.prerender += vel;
}
this.lastShapeId = shape.id;
return shape.id;
},
replaceWithShape: function (shapeid, shape) {
var existing = $('#jqsshape' + shapeid),
vel = this['_draw' + shape.type].apply(this, shape.args);
existing[0].outerHTML = vel;
},
replaceWithShapes: function (shapeids, shapes) {
// replace the first shapeid with all the new shapes then toast the remaining old shapes
var existing = $('#jqsshape' + shapeids[0]),
replace = '',
slen = shapes.length,
i;
for (i = 0; i < slen; i++) {
replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);
}
existing[0].outerHTML = replace;
for (i = 1; i < shapeids.length; i++) {
$('#jqsshape' + shapeids[i]).remove();
}
},
insertAfterShape: function (shapeid, shape) {
var existing = $('#jqsshape' + shapeid),
vel = this['_draw' + shape.type].apply(this, shape.args);
existing[0].insertAdjacentHTML('afterEnd', vel);
},
removeShapeId: function (shapeid) {
var existing = $('#jqsshape' + shapeid);
this.group.removeChild(existing[0]);
},
getShapeAt: function (el, x, y) {
var shapeid = el.id.substr(8);
return shapeid;
},
render: function () {
if (!this.rendered) {
// batch the intial render into a single repaint
this.group.innerHTML = this.prerender;
this.rendered = true;
}
}
});
@@ -0,0 +1 @@
2.1.3
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+6 -6
View File
@@ -7,12 +7,12 @@
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>{{template "title" .}}</title> <title>{{template "title" .}}</title>
<link href="public/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="/public/bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="public/bower_components/bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet"> <link href="/public/bower_components/bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet">
<link href="public/inbucket.css" rel="stylesheet"> <link href="/public/inbucket.css" rel="stylesheet">
<link href="public/favicon.png" rel="shortcut icon" type="image/png"> <link href="/public/favicon.png" rel="shortcut icon" type="image/png">
<script src="public/bower_components/jquery/dist/jquery.min.js"></script> <script src="/public/bower_components/jquery/dist/jquery.min.js"></script>
<script src="public/bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <script src="/public/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
{{template "script" .}} {{template "script" .}}
</head> </head>
<body> <body>
+2 -2
View File
@@ -1,8 +1,8 @@
{{define "title"}}Inbucket Status{{end}} {{define "title"}}Inbucket Status{{end}}
{{define "script"}} {{define "script"}}
<script src="/public/jquery.sparkline.min.js" type="text/javascript" charset="utf-8"></script> <script src="/public/bower_components/jquery-color/jquery.color.js"></script>
<script src="/public/jquery.color-2.1.2.min.js" type="text/javascript" charset="utf-8"></script> <script src="/public/bower_components/jquery-sparkline/dist/jquery.sparkline.min.js"></script>
<script src="/public/metrics.js" type="text/javascript" charset="utf-8"></script> <script src="/public/metrics.js" type="text/javascript" charset="utf-8"></script>
<script> <script>
$(document).ready( $(document).ready(