jquery-svg-rails 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/CODE_OF_CONDUCT.md +28 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +55 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/jquery-svg-rails.gemspec +26 -0
- data/lib/jquery/svg/rails.rb +9 -0
- data/lib/jquery/svg/rails/engine.rb +8 -0
- data/lib/jquery/svg/rails/version.rb +7 -0
- data/vendor/assets/javascripts/jquery.svg.js +1352 -0
- data/vendor/assets/javascripts/jquery.svg.min.js +6 -0
- data/vendor/assets/javascripts/jquery.svganim.js +471 -0
- data/vendor/assets/javascripts/jquery.svganim.min.js +6 -0
- data/vendor/assets/javascripts/jquery.svgdom.js +239 -0
- data/vendor/assets/javascripts/jquery.svgdom.min.js +6 -0
- data/vendor/assets/javascripts/jquery.svgfilter.js +368 -0
- data/vendor/assets/javascripts/jquery.svgfilter.min.js +6 -0
- data/vendor/assets/javascripts/jquery.svggraph.js +1539 -0
- data/vendor/assets/javascripts/jquery.svggraph.min.js +6 -0
- data/vendor/assets/javascripts/jquery.svgplot.js +813 -0
- data/vendor/assets/javascripts/jquery.svgplot.min.js +6 -0
- data/vendor/assets/stylesheets/jquery.svg.css +10 -0
- metadata +134 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
/* http://keith-wood.name/svg.html
|
2
|
+
SVG graphing extension for jQuery v1.5.0.
|
3
|
+
Written by Keith Wood (kbwood{at}iinet.com.au) August 2007.
|
4
|
+
Available under the MIT (http://keith-wood.name/licence.html) license.
|
5
|
+
Please attribute the author if you use it. */
|
6
|
+
(function($){$.svg.addExtension('graph',SVGGraph);$.svg.graphing=new SVGGraphing();function SVGGraphing(){this.regional=[];this.regional['']={percentageText:'Percentage'};this.region=this.regional['']}$.extend(SVGGraphing.prototype,{_chartTypes:[],addChartType:function(a,b){this._chartTypes[a]=b},chartTypes:function(){return this._chartTypes}});function SVGGraph(a){this._wrapper=a;this._drawNow=false;for(var b in $.svg.graphing._chartTypes){this._chartType=$.svg.graphing._chartTypes[b];break}this._chartOptions={};this._title={value:'',offset:25,settings:{textAnchor:'middle'}};this._area=[0.1,0.1,0.8,0.9];this._chartFormat={fill:'none',stroke:'black'};this._gridlines=[];this._series=[];this._onstatus=null;this._chartCont=this._wrapper.svg(0,0,0,0,{class_:'svg-graph'});this.xAxis=new SVGGraphAxis(this);this.xAxis.title('',40);this.yAxis=new SVGGraphAxis(this);this.yAxis.title('',40);this.x2Axis=null;this.y2Axis=null;this.legend=new SVGGraphLegend(this);this._drawNow=true}$.extend(SVGGraph.prototype,{X:0,Y:1,W:2,H:3,L:0,T:1,R:2,B:3,_percentageAxis:new SVGGraphAxis(this,$.svg.graphing.region.percentageText,0,100,10,0),container:function(a){if(arguments.length===0){return this._chartCont}this._chartCont=a;return this},chartType:function(a,b){return(arguments.length===0?this.type():this.type(a,b))},type:function(a,b){if(arguments.length===0){return this._chartType}var c=$.svg.graphing._chartTypes[a];if(c){this._chartType=c;this._chartOptions=$.extend({},b||{})}this._drawGraph();return this},chartOptions:function(a){return(arguments.length===0?this.options():this.options(a))},options:function(a){if(arguments.length===0){return this._chartOptions}this._chartOptions=$.extend({},a);this._drawGraph();return this},chartFormat:function(a,b,c){return(arguments.length===0?this.format():this.format(a,b,c))},format:function(a,b,c){if(arguments.length===0){return this._chartFormat}if(typeof b==='object'){c=b;b=null}this._chartFormat=$.extend({fill:a},(b?{stroke:b}:{}),c||{});this._drawGraph();return this},chartArea:function(a,b,c,d){return(arguments.length===0?this.area():this.area(a,b,c,d))},area:function(a,b,c,d){if(arguments.length===0){return this._area}this._area=($.isArray(a)?a:[a,b,c,d]);this._drawGraph();return this},gridlines:function(a,b){if(arguments.length===0){return this._gridlines}this._gridlines=[(typeof a==='string'?{stroke:a}:a),(typeof b==='string'?{stroke:b}:b)];if(this._gridlines[0]==null&&this._gridlines[1]==null){this._gridlines=[]}this._drawGraph();return this},title:function(a,b,c,d){if(arguments.length===0){return this._title}if(typeof b!=='number'){d=c;c=b;b=null}if(typeof c!=='string'){d=c;c=null}this._title={value:a,offset:b||this._title.offset,settings:$.extend({textAnchor:'middle'},(c?{fill:c}:{}),d||{})};this._drawGraph();return this},addSeries:function(a,b,c,d,e,f){this._series.push(new SVGGraphSeries(this,a,b,c,d,e,f));this._drawGraph();return this},series:function(i){return(arguments.length>0?this._series[i]:null)||this._series},noDraw:function(){this._drawNow=false;return this},redraw:function(){this._drawNow=true;this._drawGraph();return this},status:function(a){this._onstatus=a;return this},_drawGraph:function(){if(!this._drawNow){return}while(this._chartCont.firstChild){this._chartCont.removeChild(this._chartCont.firstChild)}if(!this._chartCont.parent){this._wrapper._svg.appendChild(this._chartCont)}if(!this._chartCont.width){this._chartCont.setAttribute('width',parseInt(this._chartCont.getAttribute('width'),10)||this._wrapper.width())}else if(this._chartCont.width.baseVal){this._chartCont.width.baseVal.value=this._chartCont.width.baseVal.value||this._wrapper.width()}else{this._chartCont.width=this._chartCont.width||this._wrapper.width()}if(!this._chartCont.height){this._chartCont.setAttribute('height',parseInt(this._chartCont.getAttribute('height'),10)||this._wrapper.height())}else if(this._chartCont.height.baseVal){this._chartCont.height.baseVal.value=this._chartCont.height.baseVal.value||this._wrapper.height()}else{this._chartCont.height=this._chartCont.height||this._wrapper.height()}this._chartType.drawGraph(this)},_getValue:function(a,b){return(!a[b]?parseInt(a.getAttribute(b),10):(a[b].baseVal?a[b].baseVal.value:a[b]))},_drawTitle:function(){this._wrapper.text(this._chartCont,this._getValue(this._chartCont,'width')/2,this._title.offset,this._title.value,this._title.settings)},_getDims:function(a){a=a||this._area;var b=this._getValue(this._chartCont,'width');var c=this._getValue(this._chartCont,'height');var d=(a[this.L]>1?a[this.L]:b*a[this.L]);var e=(a[this.T]>1?a[this.T]:c*a[this.T]);var f=(a[this.R]>1?a[this.R]:b*a[this.R])-d;var g=(a[this.B]>1?a[this.B]:c*a[this.B])-e;return[d,e,f,g]},_drawChartBackground:function(a,b){var c=this._wrapper.group(this._chartCont,{class_:'background'});var d=this._getDims();this._wrapper.rect(c,d[this.X],d[this.Y],d[this.W],d[this.H],this._chartFormat);if(this._gridlines[0]&&this.yAxis._ticks.major&&!b){this._drawGridlines(c,this.yAxis,true,d,this._gridlines[0])}if(this._gridlines[1]&&this.xAxis._ticks.major&&!a){this._drawGridlines(c,this.xAxis,false,d,this._gridlines[1])}return c},_drawGridlines:function(a,b,c,d,e){var g=this._wrapper.group(a,e);var f=(c?d[this.H]:d[this.W])/(b._scale.max-b._scale.min);var h=Math.floor(b._scale.min/b._ticks.major)*b._ticks.major;h=(h<b._scale.min?h+b._ticks.major:h);while(h<=b._scale.max){var v=(c?b._scale.max-h:h-b._scale.min)*f+(c?d[this.Y]:d[this.X]);this._wrapper.line(g,(c?d[this.X]:v),(c?v:d[this.Y]),(c?d[this.X]+d[this.W]:v),(c?v:d[this.Y]+d[this.H]));h+=b._ticks.major}},_drawAxes:function(a){var b=this._getDims();if(this.xAxis&&!a){if(this.xAxis._title){this._wrapper.text(this._chartCont,b[this.X]+b[this.W]/2,b[this.Y]+b[this.H]+this.xAxis._titleOffset,this.xAxis._title,this.xAxis._titleFormat)}this._drawAxis(this.xAxis,'xAxis',b[this.X],b[this.Y]+b[this.H],b[this.X]+b[this.W],b[this.Y]+b[this.H])}if(this.yAxis){if(this.yAxis._title){this._wrapper.text(this._chartCont,0,0,this.yAxis._title,$.extend({textAnchor:'middle',transform:'translate('+(b[this.X]-this.yAxis._titleOffset)+','+(b[this.Y]+b[this.H]/2)+') rotate(-90)'},this.yAxis._titleFormat||{}))}this._drawAxis(this.yAxis,'yAxis',b[this.X],b[this.Y],b[this.X],b[this.Y]+b[this.H])}if(this.x2Axis&&!a){if(this.x2Axis._title){this._wrapper.text(this._chartCont,b[this.X]+b[this.W]/2,b[this.X]-this.x2Axis._titleOffset,this.x2Axis._title,this.x2Axis._titleFormat)}this._drawAxis(this.x2Axis,'x2Axis',b[this.X],b[this.Y],b[this.X]+b[this.W],b[this.Y])}if(this.y2Axis){if(this.y2Axis._title){this._wrapper.text(this._chartCont,0,0,this.y2Axis._title,$.extend({textAnchor:'middle',transform:'translate('+(b[this.X]+b[this.W]+this.y2Axis._titleOffset)+','+(b[this.Y]+b[this.H]/2)+') rotate(-90)'},this.y2Axis._titleFormat||{}))}this._drawAxis(this.y2Axis,'y2Axis',b[this.X]+b[this.W],b[this.Y],b[this.X]+b[this.W],b[this.Y]+b[this.H])}},_drawAxis:function(a,b,c,d,e,f){var g=(d===f);var h=this._wrapper.group(this._chartCont,$.extend({class_:b},a._lineFormat));var i=this._wrapper.group(this._chartCont,$.extend({class_:b+'Labels',textAnchor:(g?'middle':'end')},a._labelFormat));this._wrapper.line(h,c,d,e,f);if(a._ticks.major){var j=(e>(this._getValue(this._chartCont,'width')/2)&&f>(this._getValue(this._chartCont,'height')/2));var k=(g?e-c:f-d)/(a._scale.max-a._scale.min);var l=a._ticks.size;var m=Math.floor(a._scale.min/a._ticks.major)*a._ticks.major;m=(m<a._scale.min?m+a._ticks.major:m);var n=(!a._ticks.minor?a._scale.max+1:Math.floor(a._scale.min/a._ticks.minor)*a._ticks.minor);n=(n<a._scale.min?n+a._ticks.minor:n);var o=this._getTickOffsets(a,j);var p=0;while(m<=a._scale.max||n<=a._scale.max){var q=Math.min(m,n);var r=(q===m?l:l/2);var v=(g?c:d)+(g?q-a._scale.min:a._scale.max-q)*k;this._wrapper.line(h,(g?v:c+r*o[0]),(g?d+r*o[0]:v),(g?v:c+r*o[1]),(g?d+r*o[1]:v));if(q===m){this._wrapper.text(i,(g?v:c-l),(g?d+2*l:v),(a._labels?a._labels[p++]:''+q))}m+=(q===m?a._ticks.major:0);n+=(q===n?a._ticks.minor:0)}}},_getTickOffsets:function(a,b){return[(a._ticks.position===(b?'in':'out')||a._ticks.position==='both'?-1:0),(a._ticks.position===(b?'out':'in')||a._ticks.position==='both'?+1:0),]},_getPercentageAxis:function(){this._percentageAxis._title=$.svg.graphing.region.percentageText;return this._percentageAxis},_getTotals:function(){var a=[];var b=(this._series.length?this._series[0]._values.length:0);for(var i=0;i<b;i++){a[i]=0;for(var j=0;j<this._series.length;j++){a[i]+=this._series[j]._values[i]}}return a},_drawLegend:function(){if(!this.legend._show){return}var g=this._wrapper.group(this._chartCont,{class_:'legend'});var a=this._getDims(this.legend._area);this._wrapper.rect(g,a[this.X],a[this.Y],a[this.W],a[this.H],this.legend._bgSettings);var b=a[this.W]>a[this.H];var c=this._series.length;var d=(b?a[this.W]:a[this.H])/c;var e=a[this.X]+5;var f=a[this.Y]+((b?a[this.H]:d)+this.legend._sampleSize)/2;for(var i=0;i<c;i++){var h=this._series[i];this._wrapper.rect(g,e+(b?i*d:0),f+(b?0:i*d)-this.legend._sampleSize,this.legend._sampleSize,this.legend._sampleSize,{fill:h._fill,stroke:h._stroke,strokeWidth:1});this._wrapper.text(g,e+(b?i*d:0)+this.legend._sampleSize+5,f+(b?0:i*d),h._name,this.legend._textSettings)}},_showStatus:function(a,b,c){var d=this._onstatus;if(this._onstatus){$(a).hover(function(){d.apply(this,[b,c])},function(){d.apply(this,['',0])})}}});function SVGGraphSeries(a,b,c,d,e,f,g){if(typeof b!=='string'){g=f;f=e;e=d;d=c;c=b;b=null}if(typeof e!=='string'){g=f;f=e;e=null}if(typeof f!=='number'){g=f;f=null}this._graph=a;this._name=b||'';this._values=c||[];this._axis=1;this._fill=d||'green';this._stroke=e||'black';this._strokeWidth=f||1;this._settings=g||{}}$.extend(SVGGraphSeries.prototype,{name:function(a){if(arguments.length===0){return this._name}this._name=a;this._graph._drawGraph();return this},values:function(a,b){if(arguments.length===0){return this._values}if($.isArray(a)){b=a;a=null}this._name=a||this._name;this._values=b;this._graph._drawGraph();return this},format:function(a,b,c,d){if(arguments.length===0){return $.extend({fill:this._fill,stroke:this._stroke,strokeWidth:this._strokeWidth},this._settings)}if(typeof b!=='string'){d=c;c=b;b=null}if(typeof c!=='number'){d=c;c=null}this._fill=a||this._fill;this._stroke=b||this._stroke;this._strokeWidth=c||this._strokeWidth;$.extend(this._settings,d||{});this._graph._drawGraph();return this},end:function(){return this._graph}});function SVGGraphAxis(a,b,c,d,e,f){this._graph=a;this._title=b||'';this._titleFormat={};this._titleOffset=0;this._labels=null;this._labelFormat={};this._lineFormat={stroke:'black',strokeWidth:1};this._ticks={major:e||10,minor:f||0,size:10,position:'out'};this._scale={min:c||0,max:d||100};this._crossAt=0}$.extend(SVGGraphAxis.prototype,{scale:function(a,b){if(arguments.length===0){return this._scale}this._scale.min=a;this._scale.max=b;this._graph._drawGraph();return this},ticks:function(a,b,c,d){if(arguments.length===0){return this._ticks}if(typeof c==='string'){d=c;c=null}this._ticks.major=a;this._ticks.minor=b;this._ticks.size=c||this._ticks.size;this._ticks.position=d||this._ticks.position;this._graph._drawGraph();return this},title:function(a,b,c,d){if(arguments.length===0){return{title:this._title,offset:this._titleOffset,format:this._titleFormat}}if(typeof b!=='number'){d=c;c=b;b=null}if(typeof c!=='string'){d=c;c=null}this._title=a;this._titleOffset=(b!=null?b:this._titleOffset);if(c||d){this._titleFormat=$.extend(d||{},(c?{fill:c}:{}))}this._graph._drawGraph();return this},labels:function(a,b,c){if(arguments.length===0){return{labels:this._labels,format:this._labelFormat}}if(typeof b!=='string'){c=b;b=null}this._labels=a;if(b||c){this._labelFormat=$.extend(c||{},(b?{fill:b}:{}))}this._graph._drawGraph();return this},line:function(a,b,c){if(arguments.length===0){return this._lineFormat}if(typeof b==='object'){c=b;b=null}$.extend(this._lineFormat,{stroke:a},(b?{strokeWidth:b}:{}),c||{});this._graph._drawGraph();return this},end:function(){return this._graph}});function SVGGraphLegend(a,b,c){this._graph=a;this._show=true;this._area=[0.9,0.1,1.0,0.9];this._sampleSize=15;this._bgSettings=b||{stroke:'gray'};this._textSettings=c||{}}$.extend(SVGGraphLegend.prototype,{show:function(a){if(arguments.length===0){return this._show}this._show=a;this._graph._drawGraph();return this},area:function(a,b,c,d){if(arguments.length===0){return this._area}this._area=($.isArray(a)?a:[a,b,c,d]);this._graph._drawGraph();return this},settings:function(a,b,c){if(arguments.length===0){return{sampleSize:this._sampleSize,bgSettings:this._bgSettings,textSettings:this._textSettings}}if(typeof a!=='number'){c=b;b=a;a=null}this._sampleSize=a||this._sampleSize;this._bgSettings=b;this._textSettings=c||this._textSettings;this._graph._drawGraph();return this},end:function(){return this._graph}});function roundNumber(a,b){return Math.round(a*Math.pow(10,b))/Math.pow(10,b)}var B=['barWidth (number) - the width of each bar','barGap (number) - the gap between sets of bars'];function SVGColumnChart(){}$.extend(SVGColumnChart.prototype,{title:function(){return'Basic column chart'},description:function(){return'Compare sets of values as vertical bars with grouped categories.'},options:function(){return B},drawGraph:function(a){a._drawChartBackground(true);var b=a._chartOptions.barWidth||10;var c=a._chartOptions.barGap||10;var d=a._series.length;var e=(d?(a._series[0])._values.length:0);var f=a._getDims();var g=f[a.W]/((d*b+c)*e+c);var h=f[a.H]/(a.yAxis._scale.max-a.yAxis._scale.min);this._chart=a._wrapper.group(a._chartCont,{class_:'chart'});for(var i=0;i<d;i++){this._drawSeries(a,i,d,b,c,f,g,h)}a._drawTitle();a._drawAxes(true);this._drawXAxis(a,d,e,b,c,f,g);a._drawLegend()},_drawSeries:function(a,b,c,d,e,f,h,j){var k=a._series[b];var g=a._wrapper.group(this._chart,$.extend({class_:'series'+b,fill:k._fill,stroke:k._stroke,strokeWidth:k._strokeWidth},k._settings||{}));for(var i=0;i<k._values.length;i++){var r=a._wrapper.rect(g,f[a.X]+h*(e+i*(c*d+e)+(b*d)),f[a.Y]+j*(a.yAxis._scale.max-k._values[i]),h*d,j*k._values[i]);a._showStatus(r,k._name,k._values[i])}},_drawXAxis:function(a,b,c,d,e,f,g){var h=a.xAxis;if(h._title){a._wrapper.text(a._chartCont,f[a.X]+f[a.W]/2,f[a.Y]+f[a.H]+h._titleOffset,h._title,$.extend({textAnchor:'middle'},h._titleFormat||{}))}var j=a._wrapper.group(a._chartCont,$.extend({class_:'xAxis'},h._lineFormat));var k=a._wrapper.group(a._chartCont,$.extend({class_:'xAxisLabels',textAnchor:'middle'},h._labelFormat));a._wrapper.line(j,f[a.X],f[a.Y]+f[a.H],f[a.X]+f[a.W],f[a.Y]+f[a.H]);if(h._ticks.major){var l=a._getTickOffsets(h,true);for(var i=1;i<c;i++){var x=f[a.X]+g*(e/2+i*(b*d+e));a._wrapper.line(j,x,f[a.Y]+f[a.H]+l[0]*h._ticks.size,x,f[a.Y]+f[a.H]+l[1]*h._ticks.size)}for(var i=0;i<c;i++){var x=f[a.X]+g*(e/2+(i+0.5)*(b*d+e));a._wrapper.text(k,x,f[a.Y]+f[a.H]+2*h._ticks.size,(h._labels?h._labels[i]:''+i))}}}});function SVGStackedColumnChart(){}$.extend(SVGStackedColumnChart.prototype,{title:function(){return'Stacked column chart'},description:function(){return'Compare sets of values as vertical bars showing '+'relative contributions to the whole for each category.'},options:function(){return B},drawGraph:function(a){var b=a._drawChartBackground(true,true);var c=a._getDims();if(a._gridlines[0]&&a.xAxis._ticks.major){a._drawGridlines(b,a._getPercentageAxis(),true,c,a._gridlines[0])}var d=a._chartOptions.barWidth||10;var e=a._chartOptions.barGap||10;var f=a._series.length;var g=(f?(a._series[0])._values.length:0);var h=c[a.W]/((d+e)*g+e);var i=c[a.H];this._chart=a._wrapper.group(a._chartCont,{class_:'chart'});this._drawColumns(a,f,g,d,e,c,h,i);a._drawTitle();a._wrapper.text(a._chartCont,0,0,$.svg.graphing.region.percentageText,$.extend({textAnchor:'middle',transform:'translate('+(c[a.X]-a.yAxis._titleOffset)+','+(c[a.Y]+c[a.H]/2)+') rotate(-90)'},a.yAxis._titleFormat||{}));var j=$.extend({},a._getPercentageAxis());$.extend(j._labelFormat,a.yAxis._labelFormat||{});a._drawAxis(j,'yAxis',c[a.X],c[a.Y],c[a.X],c[a.Y]+c[a.H]);this._drawXAxis(a,g,d,e,c,h);a._drawLegend()},_drawColumns:function(a,b,c,d,e,f,h,j){var k=a._getTotals();var l=[];for(var i=0;i<c;i++){l[i]=0}for(var s=0;s<b;s++){var m=a._series[s];var g=a._wrapper.group(this._chart,$.extend({class_:'series'+s,fill:m._fill,stroke:m._stroke,strokeWidth:m._strokeWidth},m._settings||{}));for(var i=0;i<m._values.length;i++){l[i]+=m._values[i];var r=a._wrapper.rect(g,f[a.X]+h*(e+i*(d+e)),f[a.Y]+j*(k[i]-l[i])/k[i],h*d,j*m._values[i]/k[i]);a._showStatus(r,m._name,roundNumber(m._values[i]/k[i]*100,2))}}},_drawXAxis:function(a,b,c,d,e,f){var g=a.xAxis;if(g._title){a._wrapper.text(a._chartCont,e[a.X]+e[a.W]/2,e[a.Y]+e[a.H]+g._titleOffset,g._title,$.extend({textAnchor:'middle'},g._titleFormat||{}))}var h=a._wrapper.group(a._chartCont,$.extend({class_:'xAxis'},g._lineFormat));var j=a._wrapper.group(a._chartCont,$.extend({class_:'xAxisLabels',textAnchor:'middle'},g._labelFormat));a._wrapper.line(h,e[a.X],e[a.Y]+e[a.H],e[a.X]+e[a.W],e[a.Y]+e[a.H]);if(g._ticks.major){var k=a._getTickOffsets(g,true);for(var i=1;i<b;i++){var x=e[a.X]+f*(d/2+i*(c+d));a._wrapper.line(h,x,e[a.Y]+e[a.H]+k[0]*g._ticks.size,x,e[a.Y]+e[a.H]+k[1]*g._ticks.size)}for(var i=0;i<b;i++){var x=e[a.X]+f*(d/2+(i+0.5)*(c+d));a._wrapper.text(j,x,e[a.Y]+e[a.H]+2*g._ticks.size,(g._labels?g._labels[i]:''+i))}}}});function SVGRowChart(){}$.extend(SVGRowChart.prototype,{title:function(){return'Basic row chart'},description:function(){return'Compare sets of values as horizontal rows with grouped categories.'},options:function(){return B},drawGraph:function(a){var b=a._drawChartBackground(true,true);var c=a._getDims();a._drawGridlines(b,a.yAxis,false,c,a._gridlines[0]);var d=a._chartOptions.barWidth||10;var e=a._chartOptions.barGap||10;var f=a._series.length;var g=(f?(a._series[0])._values.length:0);var h=c[a.W]/(a.yAxis._scale.max-a.yAxis._scale.min);var j=c[a.H]/((f*d+e)*g+e);this._chart=a._wrapper.group(a._chartCont,{class_:'chart'});for(var i=0;i<f;i++){this._drawSeries(a,i,f,d,e,c,h,j)}a._drawTitle();this._drawAxes(a,f,g,d,e,c,j);a._drawLegend()},_drawSeries:function(a,b,c,d,e,f,h,j){var k=a._series[b];var g=a._wrapper.group(this._chart,$.extend({class_:'series'+b,fill:k._fill,stroke:k._stroke,strokeWidth:k._strokeWidth},k._settings||{}));for(var i=0;i<k._values.length;i++){var r=a._wrapper.rect(g,f[a.X]+h*(0-a.yAxis._scale.min),f[a.Y]+j*(e+i*(c*d+e)+(b*d)),h*k._values[i],j*d);a._showStatus(r,k._name,k._values[i])}},_drawAxes:function(a,b,c,d,e,f,g){var h=a.yAxis;if(h){if(h._title){a._wrapper.text(a._chartCont,f[a.X]+f[a.W]/2,f[a.Y]+f[a.H]+h._titleOffset,h._title,h._titleFormat)}a._drawAxis(h,'xAxis',f[a.X],f[a.Y]+f[a.H],f[a.X]+f[a.W],f[a.Y]+f[a.H])}var h=a.xAxis;if(h._title){a._wrapper.text(a._chartCont,0,0,h._title,$.extend({textAnchor:'middle',transform:'translate('+(f[a.X]-h._titleOffset)+','+(f[a.Y]+f[a.H]/2)+') rotate(-90)'},h._titleFormat||{}))}var j=a._wrapper.group(a._chartCont,$.extend({class_:'yAxis'},h._lineFormat));var k=a._wrapper.group(a._chartCont,$.extend({class_:'yAxisLabels',textAnchor:'end'},h._labelFormat));a._wrapper.line(j,f[a.X],f[a.Y],f[a.X],f[a.Y]+f[a.H]);if(h._ticks.major){var l=a._getTickOffsets(h,false);for(var i=1;i<c;i++){var y=f[a.Y]+g*(e/2+i*(b*d+e));a._wrapper.line(j,f[a.X]+l[0]*h._ticks.size,y,f[a.X]+l[1]*h._ticks.size,y)}for(var i=0;i<c;i++){var y=f[a.Y]+g*(e/2+(i+0.5)*(b*d+e));a._wrapper.text(k,f[a.X]-h._ticks.size,y,(h._labels?h._labels[i]:''+i))}}}});function SVGStackedRowChart(){}$.extend(SVGStackedRowChart.prototype,{title:function(){return'Stacked row chart'},description:function(){return'Compare sets of values as horizontal bars showing '+'relative contributions to the whole for each category.'},options:function(){return B},drawGraph:function(a){var b=a._drawChartBackground(true,true);var c=a._getDims();if(a._gridlines[0]&&a.xAxis._ticks.major){a._drawGridlines(b,a._getPercentageAxis(),false,c,a._gridlines[0])}var d=a._chartOptions.barWidth||10;var e=a._chartOptions.barGap||10;var f=a._series.length;var g=(f?(a._series[0])._values.length:0);var h=c[a.W];var i=c[a.H]/((d+e)*g+e);this._chart=a._wrapper.group(a._chartCont,{class_:'chart'});this._drawRows(a,f,g,d,e,c,h,i);a._drawTitle();a._wrapper.text(a._chartCont,c[a.X]+c[a.W]/2,c[a.Y]+c[a.H]+a.xAxis._titleOffset,$.svg.graphing.region.percentageText,$.extend({textAnchor:'middle'},a.yAxis._titleFormat||{}));var j=$.extend({},a._getPercentageAxis());$.extend(j._labelFormat,a.yAxis._labelFormat||{});a._drawAxis(j,'xAxis',c[a.X],c[a.Y]+c[a.H],c[a.X]+c[a.W],c[a.Y]+c[a.H]);this._drawYAxis(a,g,d,e,c,i);a._drawLegend()},_drawRows:function(a,b,c,d,e,f,h,j){var k=a._getTotals();var l=[];for(var i=0;i<c;i++){l[i]=0}for(var s=0;s<b;s++){var m=a._series[s];var g=a._wrapper.group(this._chart,$.extend({class_:'series'+s,fill:m._fill,stroke:m._stroke,strokeWidth:m._strokeWidth},m._settings||{}));for(var i=0;i<m._values.length;i++){var r=a._wrapper.rect(g,f[a.X]+h*l[i]/k[i],f[a.Y]+j*(e+i*(d+e)),h*m._values[i]/k[i],j*d);a._showStatus(r,m._name,roundNumber(m._values[i]/k[i]*100,2));l[i]+=m._values[i]}}},_drawYAxis:function(a,b,c,d,e,f){var g=a.xAxis;if(g._title){a._wrapper.text(a._chartCont,0,0,g._title,$.extend({textAnchor:'middle',transform:'translate('+(e[a.X]-g._titleOffset)+','+(e[a.Y]+e[a.H]/2)+') rotate(-90)'},g._titleFormat||{}))}var h=a._wrapper.group(a._chartCont,$.extend({class_:'yAxis'},g._lineFormat));var j=a._wrapper.group(a._chartCont,$.extend({class_:'yAxisLabels',textAnchor:'end'},g._labelFormat));a._wrapper.line(h,e[a.X],e[a.Y],e[a.X],e[a.Y]+e[a.H]);if(g._ticks.major){var k=a._getTickOffsets(g,false);for(var i=1;i<b;i++){var y=e[a.Y]+f*(d/2+i*(c+d));a._wrapper.line(h,e[a.X]+k[0]*g._ticks.size,y,e[a.X]+k[1]*g._ticks.size,y)}for(var i=0;i<b;i++){var y=e[a.Y]+f*(d/2+(i+0.5)*(c+d));a._wrapper.text(j,e[a.X]-g._ticks.size,y,(g._labels?g._labels[i]:''+i))}}}});function SVGLineChart(){}$.extend(SVGLineChart.prototype,{title:function(){return'Basic line chart'},description:function(){return'Compare sets of values as continuous lines.'},options:function(){return[]},drawGraph:function(a){a._drawChartBackground();var b=a._getDims();var c=b[a.W]/(a.xAxis._scale.max-a.xAxis._scale.min);var d=b[a.H]/(a.yAxis._scale.max-a.yAxis._scale.min);this._chart=a._wrapper.group(a._chartCont,{class_:'chart'});for(var i=0;i<a._series.length;i++){this._drawSeries(a,i,b,c,d)}a._drawTitle();a._drawAxes();a._drawLegend()},_drawSeries:function(a,b,c,d,e){var f=a._series[b];var g=a._wrapper.createPath();for(var i=0;i<f._values.length;i++){var x=c[a.X]+i*d;var y=c[a.Y]+(a.yAxis._scale.max-f._values[i])*e;if(i===0){g.move(x,y)}else{g.line(x,y)}}var p=a._wrapper.path(this._chart,g,$.extend({id:'series'+b,fill:'none',stroke:f._stroke,strokeWidth:f._strokeWidth},f._settings||{}));a._showStatus(p,f._name,0)}});function SVGPieChart(){}$.extend(SVGPieChart.prototype,{_options:['explode (number or number[]) - indexes of sections to explode out of the pie','explodeDist (number) - the distance to move an exploded section','pieGap (number) - the distance between pies for multiple values'],title:function(){return'Pie chart'},description:function(){return'Compare relative sizes of values as contributions to the whole.'},options:function(){return this._options},drawGraph:function(a){a._drawChartBackground(true,true);this._chart=a._wrapper.group(a._chartCont,{class_:'chart'});var b=a._getDims();this._drawSeries(a,b);a._drawTitle();a._drawLegend()},_drawSeries:function(a,b){var c=a._getTotals();var d=a._series.length;var e=(d?(a._series[0])._values.length:0);var f=a._wrapper.createPath();var g=a._chartOptions.explode||[];g=($.isArray(g)?g:[g]);var h=a._chartOptions.explodeDist||10;var l=(e<=1?0:a._chartOptions.pieGap||10);var m=(b[a.W]-(e*l)-l)/e/2;var n=b[a.H]/2;var o=Math.min(m,n)-(g.length>0?h:0);var q=a._wrapper.group(a._chartCont,$.extend({class_:'xAxisLabels',textAnchor:'middle'},a.xAxis._labelFormat));var r=[];for(var i=0;i<e;i++){var s=b[a.X]+m+(i*(2*Math.min(m,n)+l))+l;var t=b[a.Y]+n;var u=0;for(var j=0;j<d;j++){var v=a._series[j];if(i===0){r[j]=a._wrapper.group(this._chart,$.extend({class_:'series'+j,fill:v._fill,stroke:v._stroke,strokeWidth:v._strokeWidth},v._settings||{}))}if(v._values[i]===0){continue}var w=(u/c[i])*2*Math.PI;u+=v._values[i];var z=(u/c[i])*2*Math.PI;var A=false;for(var k=0;k<g.length;k++){if(g[k]===j){A=true;break}}var x=s+(A?h*Math.cos((w+z)/2):0);var y=t+(A?h*Math.sin((w+z)/2):0);var p=a._wrapper.path(r[j],f.reset().move(x,y).line(x+o*Math.cos(w),y+o*Math.sin(w)).arc(o,o,0,(z-w<Math.PI?0:1),1,x+o*Math.cos(z),y+o*Math.sin(z)).close());a._showStatus(p,v._name,roundNumber((z-w)/2/Math.PI*100,2))}if(a.xAxis){a._wrapper.text(q,s,b[a.Y]+b[a.H]+a.xAxis._titleOffset,a.xAxis._labels[i])}}}});$.svg.graphing.addChartType('column',new SVGColumnChart());$.svg.graphing.addChartType('stackedColumn',new SVGStackedColumnChart());$.svg.graphing.addChartType('row',new SVGRowChart());$.svg.graphing.addChartType('stackedRow',new SVGStackedRowChart());$.svg.graphing.addChartType('line',new SVGLineChart());$.svg.graphing.addChartType('pie',new SVGPieChart())})(jQuery)
|
@@ -0,0 +1,813 @@
|
|
1
|
+
/* http://keith-wood.name/svg.html
|
2
|
+
SVG plotting extension for jQuery v1.5.0.
|
3
|
+
Written by Keith Wood (kbwood{at}iinet.com.au) December 2008.
|
4
|
+
Available under the MIT (http://keith-wood.name/licence.html) license.
|
5
|
+
Please attribute the author if you use it. */
|
6
|
+
|
7
|
+
(function($) { // Hide scope, no $ conflict
|
8
|
+
|
9
|
+
$.svg.addExtension('plot', SVGPlot);
|
10
|
+
|
11
|
+
/** The SVG plotting manager.
|
12
|
+
<p>Use the singleton instance of this class, $.svg.plot,
|
13
|
+
to interact with the SVG plotting functionality.</p>
|
14
|
+
@module SVGPlot */
|
15
|
+
function SVGPlot(wrapper) {
|
16
|
+
this._wrapper = wrapper; // The attached SVG wrapper object
|
17
|
+
this._drawNow = false; // True for immediate update, false to wait for redraw call
|
18
|
+
// The plot title and settings
|
19
|
+
this._title = {value: '', offset: 25, settings: {textAnchor: 'middle'}};
|
20
|
+
this._area = [0.1, 0.1, 0.8, 0.9]; // The chart area: left, top, right, bottom, > 1 in pixels, <= 1 as proportion
|
21
|
+
this._areaFormat = {fill: 'none', stroke: 'black'}; // The formatting for the plot area
|
22
|
+
this._gridlines = []; // The formatting of the x- and y-gridlines
|
23
|
+
this._equalXY = true; // True for equal-sized x- and y-units, false to fill available space
|
24
|
+
this._functions = []; // The functions to be plotted, each is an object
|
25
|
+
this._onstatus = null; // The callback function for status updates
|
26
|
+
this._uuid = new Date().getTime();
|
27
|
+
this._plotCont = this._wrapper.svg(0, 0, 0, 0, {class_: 'svg-plot'}); // The main container for the plot
|
28
|
+
|
29
|
+
/** The main x-axis for this plot. */
|
30
|
+
this.xAxis = new SVGPlotAxis(this);
|
31
|
+
this.xAxis.title('X', 20);
|
32
|
+
/** The main y-axis for this plot. */
|
33
|
+
this.yAxis = new SVGPlotAxis(this);
|
34
|
+
this.yAxis.title('Y', 20);
|
35
|
+
/** The legend for this plot. */
|
36
|
+
this.legend = new SVGPlotLegend(this);
|
37
|
+
this._drawNow = true;
|
38
|
+
}
|
39
|
+
|
40
|
+
$.extend(SVGPlot.prototype, {
|
41
|
+
|
42
|
+
/* Useful indexes. */
|
43
|
+
/** Index in a dimensions array for x-coordinate. */
|
44
|
+
X: 0,
|
45
|
+
/** Index in a dimensions array for y-coordinate. */
|
46
|
+
Y: 1,
|
47
|
+
/** Index in a dimensions array for width. */
|
48
|
+
W: 2,
|
49
|
+
/** Index in a dimensions array for height. */
|
50
|
+
H: 3,
|
51
|
+
/** Index in an area array for left x-coordinate. */
|
52
|
+
L: 0,
|
53
|
+
/** Index in an area array for top y-coordinate. */
|
54
|
+
T: 1,
|
55
|
+
/** Index in an area array for right x-coordinate. */
|
56
|
+
R: 2,
|
57
|
+
/** Index in an area array for bottom y-coordinate. */
|
58
|
+
B: 3,
|
59
|
+
|
60
|
+
/** Set or retrieve the container for the plot.
|
61
|
+
@param cont {SVGElement} The container for the plot.
|
62
|
+
@return {SVGPlot|SVGElement} This plot object or the current container (if no parameters). */
|
63
|
+
container: function(cont) {
|
64
|
+
if (arguments.length === 0) {
|
65
|
+
return this._plotCont;
|
66
|
+
}
|
67
|
+
this._plotCont = cont;
|
68
|
+
return this;
|
69
|
+
},
|
70
|
+
|
71
|
+
/** Set or retrieve the main plotting area.
|
72
|
+
@param left {number|number[]} > 1 is pixels, <= 1 is proportion of width or array for left, top, right, bottom.
|
73
|
+
@param [top] {number) > 1 is pixels, <= 1 is proportion of height.
|
74
|
+
@param [right] {number) > 1 is pixels, <= 1 is proportion of width.
|
75
|
+
@param [bottom] {number) > 1 is pixels, <= 1 is proportion of height.
|
76
|
+
@return {SVGPlot|number[]} This plot object or the plotting area: left, top, right, bottom (if no parameters). */
|
77
|
+
area: function(left, top, right, bottom) {
|
78
|
+
if (arguments.length === 0) {
|
79
|
+
return this._area;
|
80
|
+
}
|
81
|
+
this._area = ($.isArray(left) ? left : [left, top, right, bottom]);
|
82
|
+
this._drawPlot();
|
83
|
+
return this;
|
84
|
+
},
|
85
|
+
|
86
|
+
/** Set or retrieve the background of the plot area.
|
87
|
+
@param fill {string} How to fill the area background.
|
88
|
+
@param [stroke] {string} The colour of the outline.
|
89
|
+
@param [settings] {object} Additional formatting for the area background.
|
90
|
+
@return {SVGPlot|object} This plot object or the area format (if no parameters). */
|
91
|
+
format: function(fill, stroke, settings) {
|
92
|
+
if (arguments.length === 0) {
|
93
|
+
return this._areaFormat;
|
94
|
+
}
|
95
|
+
if (typeof stroke === 'object') {
|
96
|
+
settings = stroke;
|
97
|
+
stroke = null;
|
98
|
+
}
|
99
|
+
this._areaFormat = $.extend({fill: fill}, (stroke ? {stroke: stroke} : {}), settings || {});
|
100
|
+
this._drawPlot();
|
101
|
+
return this;
|
102
|
+
},
|
103
|
+
|
104
|
+
/** Set or retrieve the gridlines formatting for the plot area.
|
105
|
+
@param xSettings {string|object} The colour of the gridlines along the x-axis,
|
106
|
+
or formatting for the gridlines along the x-axis, or <code>null</code> for none.
|
107
|
+
@param ySettings {string|object} The colour of the gridlines along the y-axis,
|
108
|
+
or formatting for the gridlines along the y-axis, or <code>null</code> for none.
|
109
|
+
@return {SVGPlot|object[]} This plot object or the gridlines formatting (if no parameters). */
|
110
|
+
gridlines: function(xSettings, ySettings) {
|
111
|
+
if (arguments.length === 0) {
|
112
|
+
return this._gridlines;
|
113
|
+
}
|
114
|
+
this._gridlines = [(typeof xSettings === 'string' ? {stroke: xSettings} : xSettings),
|
115
|
+
(typeof ySettings === 'string' ? {stroke: ySettings} : ySettings)];
|
116
|
+
if (this._gridlines[0] == null && this._gridlines[1] == null) {
|
117
|
+
this._gridlines = [];
|
118
|
+
}
|
119
|
+
this._drawPlot();
|
120
|
+
return this;
|
121
|
+
},
|
122
|
+
|
123
|
+
/** Set or retrieve the equality of the x- and y-axes.
|
124
|
+
@param value {boolean} <code>true</code> for equal x- and y-units,
|
125
|
+
<code>false</code> to fill the available space.
|
126
|
+
@return {SVGPlot|boolean} This plot object or the current setting (if no parameters). */
|
127
|
+
equalXY: function(value) {
|
128
|
+
if (arguments.length === 0) {
|
129
|
+
return this._equalXY;
|
130
|
+
}
|
131
|
+
this._equalXY = value;
|
132
|
+
return this;
|
133
|
+
},
|
134
|
+
|
135
|
+
/** Set or retrieve the title of the plot and its formatting.
|
136
|
+
@param value {string} The title.
|
137
|
+
@param [offset] {number} The vertical positioning of the title, > 1 is pixels, <= 1 is proportion of width.
|
138
|
+
@param [colour] {string} The colour of the title.
|
139
|
+
@param [settings] {object} Formatting for the title.
|
140
|
+
@return {SVGPlot|object} This plot object or value, offset, and settings for the title (if no parameters). */
|
141
|
+
title: function(value, offset, colour, settings) {
|
142
|
+
if (arguments.length === 0) {
|
143
|
+
return this._title;
|
144
|
+
}
|
145
|
+
if (typeof offset !== 'number') {
|
146
|
+
settings = colour;
|
147
|
+
colour = offset;
|
148
|
+
offset = null;
|
149
|
+
}
|
150
|
+
if (typeof colour !== 'string') {
|
151
|
+
settings = colour;
|
152
|
+
colour = null;
|
153
|
+
}
|
154
|
+
this._title = {value: value, offset: offset || this._title.offset,
|
155
|
+
settings: $.extend({textAnchor: 'middle'}, (colour ? {fill: colour} : {}), settings || {})};
|
156
|
+
this._drawPlot();
|
157
|
+
return this;
|
158
|
+
},
|
159
|
+
|
160
|
+
/** Add a function to be plotted on the plot.
|
161
|
+
@param [name] {string} The name of this series.
|
162
|
+
@param fn {function} The function to be plotted.
|
163
|
+
@param [range] {number[]} The range of values to plot.
|
164
|
+
@param [points] {number} The number of points to plot within this range.
|
165
|
+
@param [stroke] {string} The colour of the plotted lines.
|
166
|
+
@param [strokeWidth] {number} The width of the plotted lines.
|
167
|
+
@param [settings] {object} Additional settings for the plotted values.
|
168
|
+
@return {SVGPlot} This plot object. */
|
169
|
+
addFunction: function(name, fn, range, points, stroke, strokeWidth, settings) {
|
170
|
+
this._functions.push(new SVGPlotFunction(this, name, fn, range, points, stroke, strokeWidth, settings));
|
171
|
+
this._drawPlot();
|
172
|
+
return this;
|
173
|
+
},
|
174
|
+
|
175
|
+
/** Retrieve the function wrappers.
|
176
|
+
@param [i] {number} the function index.
|
177
|
+
@return {SVGPlotFunction|SVGPlotFunction[]} the specified function or the list of functions. */
|
178
|
+
functions: function(i) {
|
179
|
+
return (arguments.length > 0 ? this._functions[i] : null) || this._functions;
|
180
|
+
},
|
181
|
+
|
182
|
+
/** Suppress drawing of the plot until redraw() is called.
|
183
|
+
@return {SVGPlot} this plot object. */
|
184
|
+
noDraw: function() {
|
185
|
+
this._drawNow = false;
|
186
|
+
return this;
|
187
|
+
},
|
188
|
+
|
189
|
+
/** Redraw the entire plot with the current settings and values.
|
190
|
+
@return {SVGPlot} This plot object. */
|
191
|
+
redraw: function() {
|
192
|
+
this._drawNow = true;
|
193
|
+
this._drawPlot();
|
194
|
+
return this;
|
195
|
+
},
|
196
|
+
|
197
|
+
/** Set the callback function for status updates.
|
198
|
+
@param onstatus {function} The callback function.
|
199
|
+
@return {SVGPlot} This plot object. */
|
200
|
+
status: function(onstatus) {
|
201
|
+
this._onstatus = onstatus;
|
202
|
+
return this;
|
203
|
+
},
|
204
|
+
|
205
|
+
/** Actually draw the plot (if allowed).
|
206
|
+
@private */
|
207
|
+
_drawPlot: function() {
|
208
|
+
if (!this._drawNow) {
|
209
|
+
return;
|
210
|
+
}
|
211
|
+
while (this._plotCont.firstChild) {
|
212
|
+
this._plotCont.removeChild(this._plotCont.firstChild);
|
213
|
+
}
|
214
|
+
if (!this._plotCont.parent) {
|
215
|
+
this._wrapper._svg.appendChild(this._plotCont);
|
216
|
+
}
|
217
|
+
// Set sizes if not already there
|
218
|
+
if (!this._plotCont.width) {
|
219
|
+
this._plotCont.setAttribute('width',
|
220
|
+
parseInt(this._plotCont.getAttribute('width'), 10) || this._wrapper.width());
|
221
|
+
}
|
222
|
+
else if (this._plotCont.width.baseVal) {
|
223
|
+
this._plotCont.width.baseVal.value = this._plotCont.width.baseVal.value || this._wrapper.width();
|
224
|
+
}
|
225
|
+
else {
|
226
|
+
this._plotCont.width = this._plotCont.width || this._wrapper.width();
|
227
|
+
}
|
228
|
+
if (!this._plotCont.height) {
|
229
|
+
this._plotCont.setAttribute('height',
|
230
|
+
parseInt(this._plotCont.getAttribute('height'), 10) || this._wrapper.height());
|
231
|
+
}
|
232
|
+
else if (this._plotCont.height.baseVal) {
|
233
|
+
this._plotCont.height.baseVal.value = this._plotCont.height.baseVal.value || this._wrapper.height();
|
234
|
+
}
|
235
|
+
else {
|
236
|
+
this._plotCont.height = this._plotCont.height || this._wrapper.height();
|
237
|
+
}
|
238
|
+
this._drawChartBackground();
|
239
|
+
var dims = this._getDims();
|
240
|
+
var clip = this._wrapper.other(this._plotCont, 'clipPath', {id: 'clip' + this._uuid});
|
241
|
+
this._wrapper.rect(clip, dims[this.X], dims[this.Y], dims[this.W], dims[this.H]);
|
242
|
+
this._plot = this._wrapper.group(this._plotCont,
|
243
|
+
{class_: 'foreground', clipPath: 'url(#clip' + this._uuid + ')'});
|
244
|
+
this._drawAxis(true);
|
245
|
+
this._drawAxis(false);
|
246
|
+
for (var i = 0; i < this._functions.length; i++) {
|
247
|
+
this._plotFunction(this._functions[i], i);
|
248
|
+
}
|
249
|
+
this._drawTitle();
|
250
|
+
this._drawLegend();
|
251
|
+
},
|
252
|
+
|
253
|
+
/** Decode an attribute value.
|
254
|
+
@private
|
255
|
+
@param node {SVGElement} The node to examine.
|
256
|
+
@param name {string} The attribute name.
|
257
|
+
@return {string} The actual value. */
|
258
|
+
_getValue: function(node, name) {
|
259
|
+
return (!node[name] ? parseInt(node.getAttribute(name), 10) :
|
260
|
+
(node[name].baseVal ? node[name].baseVal.value : node[name]));
|
261
|
+
},
|
262
|
+
|
263
|
+
/** Calculate the actual dimensions of the plot area.
|
264
|
+
@private
|
265
|
+
@param [area] {number[]} The area values to evaluate, or the current area if not specified.
|
266
|
+
@return {number[]} An array of dimension values: left, top, width, height. */
|
267
|
+
_getDims: function(area) {
|
268
|
+
var otherArea = (area != null);
|
269
|
+
area = area || this._area;
|
270
|
+
var availWidth = this._getValue(this._plotCont, 'width');
|
271
|
+
var availHeight = this._getValue(this._plotCont, 'height');
|
272
|
+
var left = (area[this.L] > 1 ? area[this.L] : availWidth * area[this.L]);
|
273
|
+
var top = (area[this.T] > 1 ? area[this.T] : availHeight * area[this.T]);
|
274
|
+
var width = (area[this.R] > 1 ? area[this.R] : availWidth * area[this.R]) - left;
|
275
|
+
var height = (area[this.B] > 1 ? area[this.B] : availHeight * area[this.B]) - top;
|
276
|
+
if (this._equalXY && !otherArea) {
|
277
|
+
var scale = Math.min(width / (this.xAxis._scale.max - this.xAxis._scale.min),
|
278
|
+
height / (this.yAxis._scale.max - this.yAxis._scale.min));
|
279
|
+
width = scale * (this.xAxis._scale.max - this.xAxis._scale.min);
|
280
|
+
height = scale * (this.yAxis._scale.max - this.yAxis._scale.min);
|
281
|
+
}
|
282
|
+
return [left, top, width, height];
|
283
|
+
},
|
284
|
+
|
285
|
+
/** Calculate the scaling factors for the plot area.
|
286
|
+
@private
|
287
|
+
@return {number[]} The x- and y-scaling factors. */
|
288
|
+
_getScales: function() {
|
289
|
+
var dims = this._getDims();
|
290
|
+
return [dims[this.W] / (this.xAxis._scale.max - this.xAxis._scale.min),
|
291
|
+
dims[this.H] / (this.yAxis._scale.max - this.yAxis._scale.min)];
|
292
|
+
},
|
293
|
+
|
294
|
+
/** Draw the chart background, including gridlines.
|
295
|
+
@private
|
296
|
+
@param [noXGrid] {boolean} <code>true</code> to suppress the x-gridlines, <code>false</code> to draw them.
|
297
|
+
@param [noYGrid] {boolean} <code>true</code> to suppress the y-gridlines, <code>false</code> to draw them.
|
298
|
+
@return {SVGElement} The background group element. */
|
299
|
+
_drawChartBackground: function(noXGrid, noYGrid) {
|
300
|
+
var bg = this._wrapper.group(this._plotCont, {class_: 'background'});
|
301
|
+
var dims = this._getDims();
|
302
|
+
this._wrapper.rect(bg, dims[this.X], dims[this.Y], dims[this.W], dims[this.H], this._areaFormat);
|
303
|
+
if (this._gridlines[0] && this.yAxis._ticks.major && !noYGrid) {
|
304
|
+
this._drawGridlines(bg, true, this._gridlines[0], dims);
|
305
|
+
}
|
306
|
+
if (this._gridlines[1] && this.xAxis._ticks.major && !noXGrid) {
|
307
|
+
this._drawGridlines(bg, false, this._gridlines[1], dims);
|
308
|
+
}
|
309
|
+
return bg;
|
310
|
+
},
|
311
|
+
|
312
|
+
/** Draw one set of gridlines.
|
313
|
+
@private
|
314
|
+
@param bg {SVGElement} The background group element.
|
315
|
+
@param horiz {boolean} <code>true</code> if horizontal, <code>false</code> if vertical.
|
316
|
+
@param format {object} Additional settings for the gridlines. */
|
317
|
+
_drawGridlines: function(bg, horiz, format, dims) {
|
318
|
+
var g = this._wrapper.group(bg, format);
|
319
|
+
var axis = (horiz ? this.yAxis : this.xAxis);
|
320
|
+
var scales = this._getScales();
|
321
|
+
var major = Math.floor(axis._scale.min / axis._ticks.major) * axis._ticks.major;
|
322
|
+
major += (major <= axis._scale.min ? axis._ticks.major : 0);
|
323
|
+
while (major < axis._scale.max) {
|
324
|
+
var v = (horiz ? axis._scale.max - major : major - axis._scale.min) *
|
325
|
+
scales[horiz ? 1 : 0] + (horiz ? dims[this.Y] : dims[this.X]);
|
326
|
+
this._wrapper.line(g, (horiz ? dims[this.X] : v), (horiz ? v : dims[this.Y]),
|
327
|
+
(horiz ? dims[this.X] + dims[this.W] : v), (horiz ? v : dims[this.Y] + dims[this.H]));
|
328
|
+
major += axis._ticks.major;
|
329
|
+
}
|
330
|
+
},
|
331
|
+
|
332
|
+
/** Draw an axis, its tick marks, and title.
|
333
|
+
@private
|
334
|
+
@param horiz {boolean} <code>true</code> for x-axis, <code>false</code> for y-axis. */
|
335
|
+
_drawAxis: function(horiz) {
|
336
|
+
var id = (horiz ? 'x' : 'y') + 'Axis';
|
337
|
+
var axis = (horiz ? this.xAxis : this.yAxis);
|
338
|
+
var axis2 = (horiz ? this.yAxis : this.xAxis);
|
339
|
+
var dims = this._getDims();
|
340
|
+
var scales = this._getScales();
|
341
|
+
var gl = this._wrapper.group(this._plot, $.extend({class_: id}, axis._lineFormat));
|
342
|
+
var gt = this._wrapper.group(this._plot, $.extend({class_: id + 'Labels',
|
343
|
+
textAnchor: (horiz ? 'middle' : 'end')}, axis._labelFormat));
|
344
|
+
var zero = (horiz ? axis2._scale.max : -axis2._scale.min) *
|
345
|
+
scales[horiz ? 1 : 0] + (horiz ? dims[this.Y] : dims[this.X]);
|
346
|
+
this._wrapper.line(gl, (horiz ? dims[this.X] : zero), (horiz ? zero : dims[this.Y]),
|
347
|
+
(horiz ? dims[this.X] + dims[this.W] : zero), (horiz ? zero : dims[this.Y] + dims[this.H]));
|
348
|
+
if (axis._ticks.major) {
|
349
|
+
var size = axis._ticks.size;
|
350
|
+
var major = Math.floor(axis._scale.min / axis._ticks.major) * axis._ticks.major;
|
351
|
+
major = (major < axis._scale.min ? major + axis._ticks.major : major);
|
352
|
+
var minor = (!axis._ticks.minor ? axis._scale.max + 1 :
|
353
|
+
Math.floor(axis._scale.min / axis._ticks.minor) * axis._ticks.minor);
|
354
|
+
minor = (minor < axis._scale.min ? minor + axis._ticks.minor : minor);
|
355
|
+
var offsets = [(axis._ticks.position === 'nw' || axis._ticks.position === 'both' ? -1 : 0),
|
356
|
+
(axis._ticks.position === 'se' || axis._ticks.position === 'both' ? +1 : 0)];
|
357
|
+
while (major <= axis._scale.max || minor <= axis._scale.max) {
|
358
|
+
var cur = Math.min(major, minor);
|
359
|
+
var len = (cur === major ? size : size / 2);
|
360
|
+
var xy = (horiz ? cur - axis._scale.min : axis._scale.max - cur) *
|
361
|
+
scales[horiz ? 0 : 1] + (horiz ? dims[this.X] : dims[this.Y]);
|
362
|
+
this._wrapper.line(gl, (horiz ? xy : zero + len * offsets[0]), (horiz ? zero + len * offsets[0] : xy),
|
363
|
+
(horiz ? xy : zero + len * offsets[1]), (horiz ? zero + len * offsets[1] : xy));
|
364
|
+
if (cur === major && cur !== 0) {
|
365
|
+
this._wrapper.text(gt, (horiz ? xy : zero - size), (horiz ? zero - size : xy), '' + cur);
|
366
|
+
}
|
367
|
+
major += (cur === major ? axis._ticks.major : 0);
|
368
|
+
minor += (cur === minor ? axis._ticks.minor : 0);
|
369
|
+
}
|
370
|
+
}
|
371
|
+
if (axis._title) {
|
372
|
+
if (horiz) {
|
373
|
+
this._wrapper.text(this._plotCont, dims[this.X] - axis._titleOffset,
|
374
|
+
zero, axis._title, $.extend({textAnchor: 'end'}, axis._titleFormat || {}));
|
375
|
+
}
|
376
|
+
else {
|
377
|
+
this._wrapper.text(this._plotCont, zero, dims[this.Y] + dims[this.H] + axis._titleOffset,
|
378
|
+
axis._title, $.extend({textAnchor : 'middle'}, axis._titleFormat || {}));
|
379
|
+
}
|
380
|
+
}
|
381
|
+
},
|
382
|
+
|
383
|
+
/** Plot an individual function.
|
384
|
+
@private
|
385
|
+
@param fn {function} The function to plot.
|
386
|
+
@param cur {number} The current function index. */
|
387
|
+
_plotFunction: function(fn, cur) {
|
388
|
+
var dims = this._getDims();
|
389
|
+
var scales = this._getScales();
|
390
|
+
var path = this._wrapper.createPath();
|
391
|
+
var range = fn._range || [this.xAxis._scale.min, this.xAxis._scale.max];
|
392
|
+
var xScale = (range[1] - range[0]) / fn._points;
|
393
|
+
var first = true;
|
394
|
+
for (var i = 0; i <= fn._points; i++) {
|
395
|
+
var x = range[0] + i * xScale;
|
396
|
+
if (x > this.xAxis._scale.max + xScale) {
|
397
|
+
break;
|
398
|
+
}
|
399
|
+
if (x < this.xAxis._scale.min - xScale) {
|
400
|
+
continue;
|
401
|
+
}
|
402
|
+
var px = (x - this.xAxis._scale.min) * scales[0] + dims[this.X];
|
403
|
+
var py = dims[this.H] - ((fn._fn(x) - this.yAxis._scale.min) * scales[1]) + dims[this.Y];
|
404
|
+
path[(first ? 'move' : 'line') + 'To'](px, py);
|
405
|
+
first = false;
|
406
|
+
}
|
407
|
+
var p = this._wrapper.path(this._plot, path, $.extend({class_: 'fn' + cur, fill: 'none', stroke: fn._stroke,
|
408
|
+
strokeWidth: fn._strokeWidth}, fn._settings || {}));
|
409
|
+
this._showStatus(p, fn._name);
|
410
|
+
},
|
411
|
+
|
412
|
+
/** Draw the plot title - centred
|
413
|
+
@private */
|
414
|
+
_drawTitle: function() {
|
415
|
+
this._wrapper.text(this._plotCont, this._getValue(this._plotCont, 'width') / 2,
|
416
|
+
this._title.offset, this._title.value, this._title.settings);
|
417
|
+
},
|
418
|
+
|
419
|
+
/** Draw the chart legend.
|
420
|
+
@private */
|
421
|
+
_drawLegend: function() {
|
422
|
+
if (!this.legend._show) {
|
423
|
+
return;
|
424
|
+
}
|
425
|
+
var g = this._wrapper.group(this._plotCont, {class_: 'legend'});
|
426
|
+
var dims = this._getDims(this.legend._area);
|
427
|
+
this._wrapper.rect(g, dims[this.X], dims[this.Y], dims[this.W], dims[this.H], this.legend._bgSettings);
|
428
|
+
var horiz = dims[this.W] > dims[this.H];
|
429
|
+
var numFn = this._functions.length;
|
430
|
+
var offset = (horiz ? dims[this.W] : dims[this.H]) / numFn;
|
431
|
+
var xBase = dims[this.X] + 5;
|
432
|
+
var yBase = dims[this.Y] + ((horiz ? dims[this.H] : offset) + this.legend._sampleSize) / 2;
|
433
|
+
for (var i = 0; i < numFn; i++) {
|
434
|
+
var fn = this._functions[i];
|
435
|
+
this._wrapper.rect(g, xBase + (horiz ? i * offset : 0),
|
436
|
+
yBase + (horiz ? 0 : i * offset) - this.legend._sampleSize,
|
437
|
+
this.legend._sampleSize, this.legend._sampleSize, {fill: fn._stroke});
|
438
|
+
this._wrapper.text(g, xBase + (horiz ? i * offset : 0) + this.legend._sampleSize + 5,
|
439
|
+
yBase + (horiz ? 0 : i * offset), fn._name, this.legend._textSettings);
|
440
|
+
}
|
441
|
+
},
|
442
|
+
|
443
|
+
/** Show the current value status on hover.
|
444
|
+
@private
|
445
|
+
@param elem {SVGElement} The current plot element.
|
446
|
+
@param label {string} The current status label. */
|
447
|
+
_showStatus: function(elem, label) {
|
448
|
+
var status = this._onstatus;
|
449
|
+
if (this._onstatus) {
|
450
|
+
$(elem).hover(function(evt) { status.apply(this, [label]); },
|
451
|
+
function() { status.apply(this, ['']); });
|
452
|
+
}
|
453
|
+
}
|
454
|
+
});
|
455
|
+
|
456
|
+
/** A plot function definition.
|
457
|
+
@module SVGPlotFunction */
|
458
|
+
|
459
|
+
/** Details about each plot function.
|
460
|
+
<p>Created through <code>plot.addFunction()</code>.</p>
|
461
|
+
@param plot {SVGPlot} The owning plot.
|
462
|
+
@param [name] {string} The name of this function.
|
463
|
+
@param fn {function} The function to be plotted.
|
464
|
+
@param [range] {number[]} The range of values to be plotted.
|
465
|
+
@param [points] {number} The number of points to plot within this range.
|
466
|
+
@param [stroke] {string} The colour of the (out)line for the plot.
|
467
|
+
@param [strokeWidth] {number} The width of the (out)line for the plot.
|
468
|
+
@param [settings] {object} Additional settings for the plotted values.
|
469
|
+
@return {SVGPlotFunction} The new plot function object. */
|
470
|
+
function SVGPlotFunction(plot, name, fn, range, points, stroke, strokeWidth, settings) {
|
471
|
+
if (typeof name !== 'string') {
|
472
|
+
settings = strokeWidth;
|
473
|
+
strokeWidth = stroke;
|
474
|
+
stroke = points;
|
475
|
+
points = range;
|
476
|
+
range = fn;
|
477
|
+
fn = name;
|
478
|
+
name = null;
|
479
|
+
}
|
480
|
+
if (!$.isArray(range)) {
|
481
|
+
settings = strokeWidth;
|
482
|
+
strokeWidth = stroke;
|
483
|
+
stroke = points;
|
484
|
+
points = range;
|
485
|
+
range = null;
|
486
|
+
}
|
487
|
+
if (typeof points !== 'number') {
|
488
|
+
settings = strokeWidth;
|
489
|
+
strokeWidth = stroke;
|
490
|
+
stroke = points;
|
491
|
+
points = null;
|
492
|
+
}
|
493
|
+
if (typeof stroke !== 'string') {
|
494
|
+
settings = strokeWidth;
|
495
|
+
strokeWidth = stroke;
|
496
|
+
stroke = null;
|
497
|
+
}
|
498
|
+
if (typeof strokeWidth !== 'number') {
|
499
|
+
settings = strokeWidth;
|
500
|
+
strokeWidth = null;
|
501
|
+
}
|
502
|
+
this._plot = plot; // The owning plot
|
503
|
+
this._name = name || ''; // Display name
|
504
|
+
this._fn = fn || identity; // The actual function: y = fn(x)
|
505
|
+
this._range = range; // The range of values plotted
|
506
|
+
this._points = points || 100; // The number of points plotted
|
507
|
+
this._stroke = stroke || 'black'; // The line colour
|
508
|
+
this._strokeWidth = strokeWidth || 1; // The line width
|
509
|
+
this._settings = settings || {}; // Any other settings
|
510
|
+
}
|
511
|
+
|
512
|
+
$.extend(SVGPlotFunction.prototype, {
|
513
|
+
|
514
|
+
/** Set or retrieve the name for this function.
|
515
|
+
@param name {string} The function's name.
|
516
|
+
@return {SVGPlotFunction|string} This plot function object or the function name (if no parameters). */
|
517
|
+
name: function(name) {
|
518
|
+
if (arguments.length === 0) {
|
519
|
+
return this._name;
|
520
|
+
}
|
521
|
+
this._name = name;
|
522
|
+
this._plot._drawPlot();
|
523
|
+
return this;
|
524
|
+
},
|
525
|
+
|
526
|
+
/** Set or retrieve the function to be plotted.
|
527
|
+
@param [name] {string} The function's name.
|
528
|
+
@param fn {function} The function to be ploted.
|
529
|
+
@return {SVGPlotFunction|function} This plot function object or the actual function (if no parameters). */
|
530
|
+
fn: function(name, fn) {
|
531
|
+
if (arguments.length === 0) {
|
532
|
+
return this._fn;
|
533
|
+
}
|
534
|
+
if (typeof name === 'function') {
|
535
|
+
fn = name;
|
536
|
+
name = null;
|
537
|
+
}
|
538
|
+
this._name = name || this._name;
|
539
|
+
this._fn = fn;
|
540
|
+
this._plot._drawPlot();
|
541
|
+
return this;
|
542
|
+
},
|
543
|
+
|
544
|
+
/** Set or retrieve the range of values to be plotted.
|
545
|
+
@param min {number} The minimum value to be plotted.
|
546
|
+
@param max {number} The maximum value to be plotted.
|
547
|
+
@return {SVGPlotFunction|number[]} This plot function object or the value range (if no parameters). */
|
548
|
+
range: function(min, max) {
|
549
|
+
if (arguments.length === 0) {
|
550
|
+
return this._range;
|
551
|
+
}
|
552
|
+
this._range = (min == null ? null : [min, max]);
|
553
|
+
this._plot._drawPlot();
|
554
|
+
return this;
|
555
|
+
},
|
556
|
+
|
557
|
+
/** Set or retrieve the number of points to be plotted.
|
558
|
+
@param value {number} The number of points to plot.
|
559
|
+
@return {SVGPlotFunction|number} This plot function object or the number of points (if no parameters). */
|
560
|
+
points: function(value) {
|
561
|
+
if (arguments.length === 0) {
|
562
|
+
return this._points;
|
563
|
+
}
|
564
|
+
this._points = value;
|
565
|
+
this._plot._drawPlot();
|
566
|
+
return this;
|
567
|
+
},
|
568
|
+
|
569
|
+
/** Set or retrieve the formatting for this function.
|
570
|
+
@param stroke {string} The (out)line colour.
|
571
|
+
@param [strokeWidth] {number} The line's width.
|
572
|
+
@param [settings] {object} Additional formatting settings for the function.
|
573
|
+
@return {SVGPlotFunction|object} This plot function object or formatting settings (if no parameters). */
|
574
|
+
format: function(stroke, strokeWidth, settings) {
|
575
|
+
if (arguments.length === 0) {
|
576
|
+
return $.extend({stroke: this._stroke, strokeWidth: this._strokeWidth}, this._settings);
|
577
|
+
}
|
578
|
+
if (typeof strokeWidth !== 'number') {
|
579
|
+
settings = strokeWidth;
|
580
|
+
strokeWidth = null;
|
581
|
+
}
|
582
|
+
this._stroke = stroke || this._stroke;
|
583
|
+
this._strokeWidth = strokeWidth || this._strokeWidth;
|
584
|
+
$.extend(this._settings, settings || {});
|
585
|
+
this._plot._drawPlot();
|
586
|
+
return this;
|
587
|
+
},
|
588
|
+
|
589
|
+
/** Return to the parent plot.
|
590
|
+
@return {SVGPlot} The parent plot. */
|
591
|
+
end: function() {
|
592
|
+
return this._plot;
|
593
|
+
}
|
594
|
+
});
|
595
|
+
|
596
|
+
/* Default function to plot.
|
597
|
+
@param x (number) the input value
|
598
|
+
@return (number) the same value */
|
599
|
+
function identity(x) {
|
600
|
+
return x;
|
601
|
+
}
|
602
|
+
|
603
|
+
/** A plot axis definition.
|
604
|
+
@module SVGPlotAxis */
|
605
|
+
|
606
|
+
/** Details about each plot axis.
|
607
|
+
<p>Accessed through <code>plot.xAxis</code> or <code>plot.yAxis</code>.</p>
|
608
|
+
@param plot {SVGPlot} The owning plot.
|
609
|
+
@param title {string} The title of the axis.
|
610
|
+
@param min {number} The minimum value displayed on this axis.
|
611
|
+
@param max {number} The maximum value displayed on this axis.
|
612
|
+
@param major {number} The distance between major ticks.
|
613
|
+
@param [minor] {number} The distance between minor ticks.
|
614
|
+
@return {SVGPlotAxis} The new plot axis object. */
|
615
|
+
function SVGPlotAxis(plot, title, min, max, major, minor) {
|
616
|
+
this._plot = plot; // The owning plot
|
617
|
+
this._title = title || ''; // The plot's title
|
618
|
+
this._titleFormat = {}; // Formatting settings for the title
|
619
|
+
this._titleOffset = 0; // The offset for positioning the title
|
620
|
+
this._labelFormat = {}; // Formatting settings for the labels
|
621
|
+
this._lineFormat = {stroke: 'black', strokeWidth: 1}; // Formatting settings for the axis lines
|
622
|
+
this._ticks = {major: major || 10, minor: minor || 0, size: 10, position: 'both'}; // Tick mark options
|
623
|
+
this._scale = {min: min || 0, max: max || 100}; // Axis scale settings
|
624
|
+
this._crossAt = 0; // Where this axis crosses the other one. */
|
625
|
+
}
|
626
|
+
|
627
|
+
$.extend(SVGPlotAxis.prototype, {
|
628
|
+
|
629
|
+
/** Set or retrieve the scale for this axis.
|
630
|
+
@param min {number} The minimum value shown.
|
631
|
+
@param max {number} The maximum value shown.
|
632
|
+
@return {SVGPlotAxis|object} This axis object or min and max values (if no parameters). */
|
633
|
+
scale: function(min, max) {
|
634
|
+
if (arguments.length === 0) {
|
635
|
+
return this._scale;
|
636
|
+
}
|
637
|
+
this._scale.min = min;
|
638
|
+
this._scale.max = max;
|
639
|
+
this._plot._drawPlot();
|
640
|
+
return this;
|
641
|
+
},
|
642
|
+
|
643
|
+
/** Set or retrieve the ticks for this axis.
|
644
|
+
@param major {number} The distance between major ticks.
|
645
|
+
@param minor {number} The distance between minor ticks.
|
646
|
+
@param [size] {number} The length of the major ticks (minor are half).
|
647
|
+
@param [position] {string} The location of the ticks: 'nw', 'se', 'both'.
|
648
|
+
@return {SVGPlotAxis|object} This axis object or major, minor, size, and position values (if no parameters). */
|
649
|
+
ticks: function(major, minor, size, position) {
|
650
|
+
if (arguments.length === 0) {
|
651
|
+
return this._ticks;
|
652
|
+
}
|
653
|
+
if (typeof size === 'string') {
|
654
|
+
position = size;
|
655
|
+
size = null;
|
656
|
+
}
|
657
|
+
this._ticks.major = major;
|
658
|
+
this._ticks.minor = minor;
|
659
|
+
this._ticks.size = size || this._ticks.size;
|
660
|
+
this._ticks.position = position || this._ticks.position;
|
661
|
+
this._plot._drawPlot();
|
662
|
+
return this;
|
663
|
+
},
|
664
|
+
|
665
|
+
/** Set or retrieve the title for this axis.
|
666
|
+
@param title {string} The title text
|
667
|
+
@param [offset] {number} The distance to offset the title position.
|
668
|
+
@param [colour] {string} How to colour the title.
|
669
|
+
@param [format] {object} Formatting settings for the title.
|
670
|
+
@return {SVGPlotAxis|object} This axis object or title, offset, and format values (if no parameters). */
|
671
|
+
title: function(title, offset, colour, format) {
|
672
|
+
if (arguments.length === 0) {
|
673
|
+
return {title: this._title, offset: this._titleOffset, format: this._titleFormat};
|
674
|
+
}
|
675
|
+
if (typeof offset !== 'number') {
|
676
|
+
format = colour;
|
677
|
+
colour = offset;
|
678
|
+
offset = null;
|
679
|
+
}
|
680
|
+
if (typeof colour !== 'string') {
|
681
|
+
format = colour;
|
682
|
+
colour = null;
|
683
|
+
}
|
684
|
+
this._title = title;
|
685
|
+
this._titleOffset = (offset != null ? offset : this._titleOffset);
|
686
|
+
if (colour || format) {
|
687
|
+
this._titleFormat = $.extend(format || {}, (colour ? {fill: colour} : {}));
|
688
|
+
}
|
689
|
+
this._plot._drawPlot();
|
690
|
+
return this;
|
691
|
+
},
|
692
|
+
|
693
|
+
/** Set or retrieve the label format for this axis.
|
694
|
+
@param [colour] {string} How to colour the labels.
|
695
|
+
@param [format] {object} Formatting settings for the labels.
|
696
|
+
@return {SVGPlotAxis|object} This axis object or format values (if no parameters). */
|
697
|
+
format: function(colour, format) {
|
698
|
+
if (arguments.length === 0) {
|
699
|
+
return this._labelFormat;
|
700
|
+
}
|
701
|
+
if (typeof colour !== 'string') {
|
702
|
+
format = colour;
|
703
|
+
colour = null;
|
704
|
+
}
|
705
|
+
this._labelFormat = $.extend(format || {}, (colour ? {fill: colour} : {}));
|
706
|
+
this._plot._drawPlot();
|
707
|
+
return this;
|
708
|
+
},
|
709
|
+
|
710
|
+
/** Set or retrieve the line formatting for this axis.
|
711
|
+
@param colour {string} The line's colour.
|
712
|
+
@param [width] {number} The line's width.
|
713
|
+
@param [settings] {object} Additional formatting settings for the line.
|
714
|
+
@return {SVGPlotAxis|object} This axis object or line formatting values (if no parameters). */
|
715
|
+
line: function(colour, width, settings) {
|
716
|
+
if (arguments.length === 0) {
|
717
|
+
return this._lineFormat;
|
718
|
+
}
|
719
|
+
if (typeof width !== 'number') {
|
720
|
+
settings = width;
|
721
|
+
width = null;
|
722
|
+
}
|
723
|
+
$.extend(this._lineFormat, {stroke: colour, strokeWidth: width || this._lineFormat.strokeWidth}, settings || {});
|
724
|
+
this._plot._drawPlot();
|
725
|
+
return this;
|
726
|
+
},
|
727
|
+
|
728
|
+
/** Return to the parent plot.
|
729
|
+
@return {SVGPlot} The parent plot. */
|
730
|
+
end: function() {
|
731
|
+
return this._plot;
|
732
|
+
}
|
733
|
+
});
|
734
|
+
|
735
|
+
/** A plot legend definition.
|
736
|
+
@module SVGPlotLegend */
|
737
|
+
|
738
|
+
/** Details about each plot legend.
|
739
|
+
<p>Accessed through <code>plot.legend</code>.</p>
|
740
|
+
@param plot {SVGPlot} The owning plot.
|
741
|
+
@param [bgSettings] {object} Additional formatting settings for the legend background.
|
742
|
+
@param [textSettings] {object} Additional formatting settings for the legend text.
|
743
|
+
@return {SVGPlotLegend} The new plot legend object. */
|
744
|
+
function SVGPlotLegend(plot, bgSettings, textSettings) {
|
745
|
+
this._plot = plot; // The owning plot
|
746
|
+
this._show = true; // Show the legend?
|
747
|
+
this._area = [0.9, 0.1, 1.0, 0.9]; // The legend area: left, top, right, bottom,
|
748
|
+
// > 1 in pixels, <= 1 as proportion
|
749
|
+
this._sampleSize = 15; // Size of sample box
|
750
|
+
this._bgSettings = bgSettings || {stroke: 'gray'}; // Additional formatting settings for the legend background
|
751
|
+
this._textSettings = textSettings || {}; // Additional formatting settings for the text
|
752
|
+
}
|
753
|
+
|
754
|
+
$.extend(SVGPlotLegend.prototype, {
|
755
|
+
|
756
|
+
/** Set or retrieve whether the legend should be shown.
|
757
|
+
@param show {boolean} <code>true</code> to display it, <code>false</code> to hide it.
|
758
|
+
@return {SVGPlotLegend|boolean} This legend object or show the legend? (if no parameters) */
|
759
|
+
show: function(show) {
|
760
|
+
if (arguments.length === 0) {
|
761
|
+
return this._show;
|
762
|
+
}
|
763
|
+
this._show = show;
|
764
|
+
this._plot._drawPlot();
|
765
|
+
return this;
|
766
|
+
},
|
767
|
+
|
768
|
+
/** Set or retrieve the legend area.
|
769
|
+
@param left {number|number[]} > 1 is pixels, <= 1 is proportion of width or array for left, top, right, bottom.
|
770
|
+
@param [top] {number} > 1 is pixels, <= 1 is proportion of height.
|
771
|
+
@param [right] {number} > 1 is pixels, <= 1 is proportion of width.
|
772
|
+
@param [bottom] {number} > 1 is pixels, <= 1 is proportion of height.
|
773
|
+
@return {SVGPlotLegend|number[]} This legend object or the legend area:
|
774
|
+
left, top, right, bottom (if no parameters). */
|
775
|
+
area: function(left, top, right, bottom) {
|
776
|
+
if (arguments.length === 0) {
|
777
|
+
return this._area;
|
778
|
+
}
|
779
|
+
this._area = ($.isArray(left) ? left : [left, top, right, bottom]);
|
780
|
+
this._plot._drawPlot();
|
781
|
+
return this;
|
782
|
+
},
|
783
|
+
|
784
|
+
/** Set or retrieve additional settings for the legend area.
|
785
|
+
@param [sampleSize] {number} The size of the sample box to display.
|
786
|
+
@param bgSettings {object} Additional formatting settings for the legend background.
|
787
|
+
@param [textSettings] {object} Additional formatting settings for the legend text.
|
788
|
+
@return {SVGPlotLegend|object} This legend object or
|
789
|
+
bgSettings and textSettings for the legend (if no parameters). */
|
790
|
+
settings: function(sampleSize, bgSettings, textSettings) {
|
791
|
+
if (arguments.length === 0) {
|
792
|
+
return {sampleSize: this._sampleSize, bgSettings: this._bgSettings, textSettings: this._textSettings};
|
793
|
+
}
|
794
|
+
if (typeof sampleSize === 'object') {
|
795
|
+
textSettings = bgSettings;
|
796
|
+
bgSettings = sampleSize;
|
797
|
+
sampleSize = null;
|
798
|
+
}
|
799
|
+
this._sampleSize = sampleSize || this._sampleSize;
|
800
|
+
this._bgSettings = bgSettings;
|
801
|
+
this._textSettings = textSettings || this._textSettings;
|
802
|
+
this._plot._drawPlot();
|
803
|
+
return this;
|
804
|
+
},
|
805
|
+
|
806
|
+
/** Return to the parent plot.
|
807
|
+
@return {SVGPlot} The parent plot. */
|
808
|
+
end: function() {
|
809
|
+
return this._plot;
|
810
|
+
}
|
811
|
+
});
|
812
|
+
|
813
|
+
})(jQuery)
|