jquery-svg-rails 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|