1. Michel Sabchuk
  2. jqplot

Commits

cleonello  committed db1cf68

Completely reworked dashed line support. Based off of code contributed by Cory Sharp. Cory's implementation was more powerful and concise than my previous implementation. Thanks Cory!

  • Participants
  • Parent commits 0c5d489
  • Branches default

Comments (0)

Files changed (9)

File examples/dashedLines.html

View file
   <script class="code" type="text/javascript">
 
     $(document).ready(function () {
-      var s1 = [[0, 2], [1, 6], [2, 7], [3, 10]];
+      s1 = [[0, 2], [1, 6], [2, 7], [3, 10]];
+
+      // Lines can be drawn as solid, dashed or dotted with the "linePattern" option.
+      // The default is "solid".  Other basic options are "dashed" and "dotted".
 
       plot1 = $.jqplot("chart1", [s1], {
         seriesDefaults:{
-            // dashedLine option turns on/off dashed lines.
-            dashedLine: true,
+            linePattern: 'dashed',
+            showMarker: false,
+            shadow: false
+        }
+      });
+    });
+</script>
+  
+  <script class="code" type="text/javascript">
+
+    $(document).ready(function () {
+
+      s1 = [[0, 2], [1, 6], [2, 7], [3, 10]];
+
+      // Size of the dashes is proportional to the width of the line.
+
+      plot1b = $.jqplot("chart1b", [s1], {
+        seriesDefaults:{
+            linePattern: 'dashed',
+            lineWidth: 7,
+            showMarker: false,
+            shadow: false
+        }
+      });
+    });
+</script>
+
+  
+  <script class="code" type="text/javascript">
+    $(document).ready(function () {
+      s2 = [[0, 6.29], [0.1, 8.21], [0.2, 8.92], [0.3, 7.33], [0.4, 7.91], [0.5, 3.6], [0.6, 6.88], 
+      [0.7, 1.5], [0.8, 0.08], [0.9, 6.36], [1, 0.5], [1.1, 9.14], [1.2, 6.23], [1.3, 2.66], 
+      [1.4, 9.9], [1.5, 7.44], [1.6, 7.82], [1.7, 8.57], [1.8, 3.99], [1.9, 3.83], [2, 6.78], 
+      [2.1, 7.63], [2.2, 6.94], [2.3, 1.24], [2.4, 2.25], [2.5, 0.67], [2.6, 6.73], [2.7, 2.25], 
+      [2.8, 7.72], [2.9, 9.36], [3, 8.49]];
+
+      // Here is the default dotted line.
+
+      plot2 = $.jqplot("chart2", [s2], {
+        seriesDefaults:{
+            linePattern: 'dotted',
             showMarker: false,
             shadow: false
         }
   <script class="code" type="text/javascript">
     $(document).ready(function () {
 
-      var s2 = [[0, 6.285649272699648], [0.1, 8.21368819521145], [0.2, 8.922134920513773], [0.3, 7.334192889379997], [0.4, 7.906516375517576], [0.5, 3.6021095084765786], [0.6, 6.879475110724167], [0.7, 1.5032242836673793], [0.8, 0.08104934022154509], [0.9, 6.360762925374943], [1, 0.5031551258715516], [1.1, 9.138638963226924], [1.2, 6.230839952411845], [1.3, 2.6620318783438215], [1.4, 9.904049056205329], [1.5, 7.439729926653593], [1.6, 7.820158898685975], [1.7, 8.566779512084974], [1.8, 3.9887669112796953], [1.9, 3.832257554743268], [2, 6.782120315701103], [2.1, 7.633957783466761], [2.2, 6.941230512247182], [2.3, 1.244192671144675], [2.4, 2.2495930262584265], [2.5, 0.6698127581945545], [2.6, 6.730093688908464], [2.7, 2.2521661852172525], [2.8, 7.719087789109827], [2.9, 9.36259733771941], [3, 8.493870267425812]];
+      // Dashes and dots work with smoothed lines as well.
 
-      plot2 = $.jqplot("chart2", [s2], {
+      plot3 = $.jqplot("chart3", [s2], {
         seriesDefaults:{
-            // The dash pattern is auto computed by default.  
-            // The smaller the point spacing, the smaller the dashes.
-            dashedLine: true,
+            linePattern: 'dashed',
             showMarker: false,
-            shadow: false
+            shadow: false,
+            rendererOptions: {
+              smooth: true
+            }
         }
       });
     });
   <script class="code" type="text/javascript">
     $(document).ready(function () {
 
-      var s3 = [[0, 3.5237602224416054], [0.030303030303030304, 7.282689933523754], [0.06060606060606061, 3.9343189282267153], [0.09090909090909091, 4.420339998792685], [0.12121212121212122, 2.6681756367160125], [0.15151515151515152, 9.676344812587905], [0.18181818181818182, 8.285454001340607], [0.21212121212121213, 2.1463131182087123], [0.24242424242424243, 3.2424333329196875], [0.2727272727272727, 2.209573487855878], [0.30303030303030304, 3.738023870244419], [0.3333333333333333, 4.94796964711754], [0.36363636363636365, 9.457841099995214], [0.3939393939393939, 6.598122361361663], [0.42424242424242425, 0.9407934085538439], [0.45454545454545453, 5.940787562591309], [0.48484848484848486, 2.746628989685088], [0.5151515151515151, 1.186682703486669], [0.5454545454545454, 8.14687470019338], [0.5757575757575758, 7.634069651628454], [0.6060606060606061, 8.987045508045497], [0.6363636363636364, 2.70612719988532], [0.6666666666666666, 6.122200623374075], [0.696969696969697, 9.888593761312015], [0.7272727272727273, 7.5143528477995725], [0.7575757575757576, 7.449471850788721], [0.7878787878787878, 3.958702096870507], [0.8181818181818182, 8.908129966846838], [0.8484848484848485, 5.392145984623756], [0.8787878787878788, 1.2125713995444232], [0.9090909090909091, 2.9043097799726447], [0.9393939393939394, 1.0688450191749432], [0.9696969696969697, 4.6469384086741705], [1, 6.339698811268097], [1.0303030303030303, 4.706667356841821], [1.0606060606060606, 5.790996246956026], [1.0909090909090908, 7.209970689302003], [1.121212121212121, 8.52079792724053], [1.1515151515151516, 8.164709451601729], [1.1818181818181819, 2.3702159486475702], [1.2121212121212122, 2.1637187478954023], [1.2424242424242424, 5.606337309494299], [1.2727272727272727, 2.592024500484701], [1.303030303030303, 6.711071628764466], [1.3333333333333333, 2.55658428937817], [1.3636363636363635, 5.637339466444738], [1.393939393939394, 9.718182462022106], [1.4242424242424243, 5.243484030231662], [1.4545454545454546, 4.527778464065558], [1.4848484848484849, 1.5322950840238847], [1.5151515151515151, 6.188980980322438], [1.5454545454545454, 4.952966224916919], [1.5757575757575757, 9.775414410655173], [1.606060606060606, 5.429312968851935], [1.6363636363636365, 7.273823962773426], [1.6666666666666667, 0.41855134292845264], [1.696969696969697, 3.5043456972980778], [1.7272727272727273, 6.5510017994231315], [1.7575757575757576, 8.648212565521563], [1.7878787878787878, 1.027653035124586], [1.8181818181818181, 3.9063019890938278], [1.8484848484848484, 2.641213682861765], [1.878787878787879, 7.191597019568393], [1.9090909090909092, 4.125003328550266], [1.9393939393939394, 5.953388871633561], [1.9696969696969697, 6.516925174329954], [2, 3.625599487569331], [2.0303030303030303, 2.7531978121230183], [2.0606060606060606, 1.8270347573076906], [2.090909090909091, 6.085170952249141], [2.121212121212121, 9.514888415612168], [2.1515151515151514, 9.85527177268489], [2.1818181818181817, 2.657980766732273], [2.212121212121212, 8.294082182398531], [2.242424242424242, 8.662744263879253], [2.272727272727273, 4.335120025506813], [2.303030303030303, 1.418931183747999], [2.3333333333333335, 4.918729754767711], [2.3636363636363638, 8.25562935405223], [2.393939393939394, 8.20946266586103], [2.4242424242424243, 4.7899901772661195], [2.4545454545454546, 0.8266049186539637], [2.484848484848485, 8.245834037511127], [2.515151515151515, 8.235452981690623], [2.5454545454545454, 2.6080325339248835], [2.5757575757575757, 3.4242172193110845], [2.606060606060606, 8.408540861633606], [2.6363636363636362, 9.860911135832119], [2.6666666666666665, 7.114667118127237], [2.696969696969697, 5.355425082373948], [2.727272727272727, 1.269411351526284], [2.757575757575758, 6.119559721604788], [2.787878787878788, 0.6334697009606927], [2.8181818181818183, 1.203759805008724], [2.8484848484848486, 5.671068948293686], [2.878787878787879, 9.181526722230032], [2.909090909090909, 9.535679673207799], [2.9393939393939394, 2.9451391277164007], [2.9696969696969697, 0.13161329043815284], [3, 7.669772828880978]];
+      // A user defined linePattern can be specified as well.  The format
+      // of a linePattern definition is an array like [dash length, gap length, ...].
+      // The line looks best when the line pattern array has an even number
+      // of elements, so it begins with a dash and ends with a gap.
+      // The dash and gap lengths are scaled to the line thickness.
 
-      plot3 = $.jqplot("chart3", [s3], {
+      plot4 = $.jqplot("chart4", [s2], {
         seriesDefaults:{
-            // With lots of points, you have very small dashes.
-            dashedLine: true,
+            linePattern: [4, 3, 1, 3, 1, 3],
             showMarker: false,
-            shadow: false
+            shadow: false,
+            rendererOptions: {
+              smooth: true
+            }
         }
       });
     });
 </script>
 
   
+<script class="code" type="text/javascript">
+    $(document).ready(function () {
+
+      // The linePattern option also accepts a shorthand string 
+      // notation of dash (-) and dot (.) characters to create
+      // a customized pattern.
+
+      plot4b = $.jqplot("chart4b", [s2], {
+        seriesDefaults:{
+            linePattern: '-.',
+            showMarker: false,
+            shadow: false,
+            rendererOptions: {
+              smooth: true
+            }
+        }
+      });
+    });
+</script>
+  
   <script class="code" type="text/javascript">
     $(document).ready(function () {
 
-      var s2 = [[0, 6.285649272699648], [0.1, 8.21368819521145], [0.2, 8.922134920513773], [0.3, 7.334192889379997], [0.4, 7.906516375517576], [0.5, 3.6021095084765786], [0.6, 6.879475110724167], [0.7, 1.5032242836673793], [0.8, 0.08104934022154509], [0.9, 6.360762925374943], [1, 0.5031551258715516], [1.1, 9.138638963226924], [1.2, 6.230839952411845], [1.3, 2.6620318783438215], [1.4, 9.904049056205329], [1.5, 7.439729926653593], [1.6, 7.820158898685975], [1.7, 8.566779512084974], [1.8, 3.9887669112796953], [1.9, 3.832257554743268], [2, 6.782120315701103], [2.1, 7.633957783466761], [2.2, 6.941230512247182], [2.3, 1.244192671144675], [2.4, 2.2495930262584265], [2.5, 0.6698127581945545], [2.6, 6.730093688908464], [2.7, 2.2521661852172525], [2.8, 7.719087789109827], [2.9, 9.36259733771941], [3, 8.493870267425812]];
+      // The default dash length and gap length can be controlled 
+      // with the dashLength and gapLength config parameters.
 
-      plot4 = $.jqplot("chart4", [s2], {
+      $.jqplot.config.dashLength = 5;
+      $.jqplot.config.gapLength = 2;
+
+      plot5 = $.jqplot("chart5", [s2], {
         seriesDefaults:{
-            dashedLine: true,
-            // You can specify your own custom dashPattern to use.
-            // dashPattern must be of the form [dash length, gap length].
-            // lengths are in pixels.
-            dashPattern: [3, 10],
+            linePattern: 'dashed',
             showMarker: false,
-            shadow: false
+            shadow: false,
+            rendererOptions: {
+              smooth: true
+            }
         }
       });
     });
     <div id="chart1" style="margin-top:20px; margin-left:20px; width:600px; height:300px;"></div>
 
     <pre class="code"></pre>
+        
+    <div id="chart1b" style="margin-top:20px; margin-left:20px; width:600px; height:300px;"></div>
+
+    <pre class="code"></pre>
 
     <div id="chart2" style="margin-top:20px; margin-left:20px; width:600px; height:300px;"></div>
 
 
     <pre class="code"></pre>
 
+    <div id="chart4b" style="margin-top:20px; margin-left:20px; width:600px; height:300px;"></div>
+
+    <pre class="code"></pre>
+
+    <div id="chart5" style="margin-top:20px; margin-left:20px; width:600px; height:300px;"></div>
+
+    <pre class="code"></pre>
+
 
   </body>
 </html>

File src/jqplot.core.js

View file
         catchErrors: false,
         defaultTickFormatString: "%.1f",
         defaultColors: [ "#4bb2c5", "#EAA228", "#c5b47f", "#579575", "#839557", "#958c12", "#953579", "#4b5de4", "#d8b83f", "#ff5800", "#0085cc", "#c747a3", "#cddf54", "#FBD178", "#26B4E3", "#bd70c7"],
-        defaultNegativeColors: [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399", "#945381", "#959E5C", "#C7AF7B", "#478396", "#907294"]
+        defaultNegativeColors: [ "#498991", "#C08840", "#9F9274", "#546D61", "#646C4A", "#6F6621", "#6E3F5F", "#4F64B0", "#A89050", "#C45923", "#187399", "#945381", "#959E5C", "#C7AF7B", "#478396", "#907294"],
+        dashLength: 4,
+        gapLength: 4,
+        dotGapLength: 2
     };
     
     
         // prop: lineCap
         // Canvas lineCap style at ends of line.
         this.lineCap = 'round';
-        // prop: dashedLine
-        // True to draw dashed instead of solid line.
-        this.dashedLine = false;
-        // auto auto computes dash pattern.
-        this.dashPattern = 'auto';
-        // prop: shadow
-        // wether or not to draw a shadow on the line
+        // prop: linePattern
+        // line pattern 'dashed', 'dotted', 'solid', some combination
+        // of '-' and '.' characters such as '.-.' or a numerical array like 
+        // [draw, skip, draw, skip, ...] such as [1, 10] to draw a dotted line, 
+        // [1, 10, 20, 10] to draw a dot-dash line, and so on.
+        this.linePattern = 'solid';
         this.shadow = true;
         // prop: shadowAngle
         // Shadow angle in degrees

File src/jqplot.linePattern.js

View file
+/**
+ * jqPlot
+ * Pure JavaScript plotting plugin using jQuery
+ *
+ * Version: @VERSION
+ *
+ * Copyright (c) 2009-2011 Chris Leonello
+ * jqPlot is currently available for use in all personal or commercial projects 
+ * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL 
+ * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can 
+ * choose the license that best suits your project and use it accordingly. 
+ *
+ * Although not required, the author would appreciate an email letting him 
+ * know of any substantial use of jqPlot.  You can reach the author at: 
+ * chris at jqplot dot com or see http://www.jqplot.com/info.php .
+ *
+ * If you are feeling kind and generous, consider supporting the project by
+ * making a donation at: http://www.jqplot.com/donate.php .
+ *
+ * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
+ *
+ *     version 2007.04.27
+ *     author Ash Searle
+ *     http://hexmen.com/blog/2007/03/printf-sprintf/
+ *     http://hexmen.com/js/sprintf.js
+ *     The author (Ash Searle) has placed this code in the public domain:
+ *     "This code is unrestricted: you are free to use it however you like."
+ * 
+ */
+
+ /**
+  * The following dashed line support contributed by Cory Sharp.
+  * After implementing an inferior method, Cory responded with a generous
+  * contribution of code and input which proved a more powerful and
+  * elegant solution.
+  */
+    
+(function($) {
+
+    var dotlen = 1e-3;
+
+    $.jqplot.LinePattern = function (ctx, pattern) {
+
+		var defaultLinePatterns = {
+			dotted: [ dotlen, $.jqplot.config.dotGapLength ],
+			dashed: [ $.jqplot.config.dashLength, $.jqplot.config.gapLength ],
+			solid: null
+		};   	
+
+        if (typeof pattern === 'string') {
+            if (pattern[0] === '.' || pattern[0] === '-') {
+                var s = pattern;
+                pattern = [];
+                for (var i=0, imax=s.length; i<imax; i++) {
+                    if (s[i] === '.') {
+                        pattern.push( dotlen );
+                    }
+                    else if (s[i] === '-') {
+                        pattern.push( $.jqplot.config.dashLength );
+                    }
+                    else {
+                        continue;
+                    }
+                    pattern.push( $.jqplot.config.gapLength );
+                }
+            }
+            else {
+                pattern = defaultLinePatterns[pattern];
+            }
+        }
+
+        if (!(pattern && pattern.length)) {
+            return ctx;
+        }
+
+        var patternIndex = 0;
+        var patternDistance = pattern[0];
+        var px = 0;
+        var py = 0;
+        var pathx0 = 0;
+        var pathy0 = 0;
+
+        var moveTo = function (x, y) {
+            ctx.moveTo( x, y );
+            px = x;
+            py = y;
+            pathx0 = x;
+            pathy0 = y;
+        };
+
+        var lineTo = function (x, y) {
+            var scale = ctx.lineWidth;
+            var dx = x - px;
+            var dy = y - py;
+            var dist = Math.sqrt(dx*dx+dy*dy);
+            if ((dist > 0) && (scale > 0)) {
+                dx /= dist;
+                dy /= dist;
+                while (true) {
+                    var dp = scale * patternDistance;
+                    if (dp < dist) {
+                        px += dp * dx;
+                        py += dp * dy;
+                        if ((patternIndex & 1) == 0) {
+                            ctx.lineTo( px, py );
+                        }
+                        else {
+                            ctx.moveTo( px, py );
+                        }
+                        dist -= dp;
+                        patternIndex++;
+                        if (patternIndex >= pattern.length) {
+                            patternIndex = 0;
+                        }
+                        patternDistance = pattern[patternIndex];
+                    }
+                    else {
+                        px = x;
+                        py = y;
+                        if ((patternIndex & 1) == 0) {
+                            ctx.lineTo( px, py );
+                        }
+                        else {
+                            ctx.moveTo( px, py );
+                        }
+                        patternDistance -= dist / scale;
+                        break;
+                    }
+                }
+            }
+        };
+
+        var beginPath = function () {
+            ctx.beginPath();
+        };
+
+        var closePath = function () {
+            lineTo( pathx0, pathy0 );
+        };
+
+        return {
+            moveTo: moveTo,
+            lineTo: lineTo,
+            beginPath: beginPath,
+            closePath: closePath
+        };
+    };
+})(jQuery);

File src/jqplot.lineRenderer.js

View file
         }
 
         // set the shape renderer options
-        var opts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.fillColor, lineWidth:this.lineWidth, closePath:this.fill};
+        var opts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, strokeStyle:this.color, fillStyle:this.fillColor, lineWidth:this.lineWidth, linePattern:this.linePattern, closePath:this.fill};
         this.renderer.shapeRenderer.init(opts);
         // set the shadow renderer options
         // scale the shadowOffset to the width of the line.
         else {
             var shadow_offset = this.shadowOffset*Math.atan((this.lineWidth/2.5))/0.785398163;
         }
-        var sopts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.lineWidth, closePath:this.fill};
+        var sopts = {lineJoin:this.lineJoin, lineCap:this.lineCap, fill:this.fill, isarc:false, angle:this.shadowAngle, offset:shadow_offset, alpha:this.shadowAlpha, depth:this.shadowDepth, lineWidth:this.lineWidth, linePattern:this.linePattern, closePath:this.fill};
         this.renderer.shadowRenderer.init(sopts);
         this._areaPoints = [];
         this._boundingBox = [[],[]];
         var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine;
         var fill = (opts.fill != undefined) ? opts.fill : this.fill;
         var fillAndStroke = (opts.fillAndStroke != undefined) ? opts.fillAndStroke : this.fillAndStroke;
-        opts.dashedLine = (opts.dashedLine != undefined) ? opts.dashedLine : this.dashedLine;
-        opts.dashPattern = (opts.dashPattern != undefined) ? opts.dashPattern : this.dashPattern;
-        opts.dashPoints = false;
         var xmin, ymin, xmax, ymax;
         ctx.save();
         if (gd.length) {
             if (showLine) {
-                // if dashed line, see if we have to compute dashpattern
-                if (opts.dashedLine && opts.dashPattern === 'auto' ) {
-                    var l = gd.length;
-                    // get average pixels between points.
-                    var fact = parseInt(gd[l-1][0] - gd[0][0]) / l;
-                    var maxfact = 24, minfact = 3;
-                    var maxdash = 10, maxgap = 14;
-                    var mindash = 1, mingap = 4;
-                    var dslope = (maxdash - mindash)/(maxfact - minfact);
-                    var gslope = (maxgap - mingap)/(maxfact - minfact);
-                    var db = maxdash - dslope * maxfact;
-                    var gb = maxgap - gslope * maxfact;
-
-                    if (fact >= maxfact) {
-                        opts.dashPattern = [maxdash, maxgap];
-                    }
-                    else if (fact >= minfact) {
-                        console.log(fact);
-                        var a = db + dslope * fact;
-                        var b = gb + gslope * fact;
-                        opts.dashPattern = [a, b];
-                    }
-                    else {
-                        opts.dashPoints = true;
-                    }
-                    console.log(opts.dashPattern);
-
-                }
-                else if (!$.isArray(opts.dashPattern)) {
-                    opts.dashPoints = true;
-                }
-
                 // if we fill, we'll have to add points to close the curve.
                 if (fill) {
                     if (this.fillToZero) { 

File src/jqplot.shadowRenderer.js

View file
         var alpha = (opts.alpha != null) ? opts.alpha : this.alpha;
         var depth = (opts.depth != null) ? opts.depth : this.depth;
         var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
+        var linePattern = (opts.linePattern != null) ? opts.linePattern : this.linePattern;
         ctx.lineWidth = (opts.lineWidth != null) ? opts.lineWidth : this.lineWidth;
         ctx.lineJoin = (opts.lineJoin != null) ? opts.lineJoin : this.lineJoin;
         ctx.lineCap = (opts.lineCap != null) ? opts.lineCap : this.lineCap;
         ctx.strokeStyle = opts.strokeStyle || this.strokeStyle || 'rgba(0,0,0,'+alpha+')';
         ctx.fillStyle = opts.fillStyle || this.fillStyle || 'rgba(0,0,0,'+alpha+')';
-        for (var k=0; k<depth; k++) {
+        for (var j=0; j<depth; j++) {
+            var ctxPattern = $.jqplot.LinePattern(ctx, linePattern);
             ctx.translate(Math.cos(this.angle*Math.PI/180)*offset, Math.sin(this.angle*Math.PI/180)*offset);
-            ctx.beginPath();
+            ctxPattern.beginPath();
             if (isarc) {
-                ctx.arc(points[0], points[1], points[2], points[3], points[4], true);  
-                if (closePath) {
-                    ctx.closePath();
-                }
-                if (fill) {
-                    ctx.fill();
-                }
-                else {
-                    ctx.stroke();
-                }              
+                ctx.arc(points[0], points[1], points[2], points[3], points[4], true);                
             }
-            else if (points && points.length) {
+            else if (points && points.length){
                 var move = true;
-                var l = points.length;
-                var pl;
-                var ang, rise, run, dashx, gapx, dashy, gapy, ndashes, x, y;
-                var dashContinuation = 0;
-                var dashTotLen = 0;
-                if (opts.dashedLine && $.isArray(opts.dashPattern)) {
-                    dashTotLen = opts.dashPattern[0] + opts.dashPattern[1]; 
-                }
-                for (var i=0; i<l; i++) {
+                for (var i=0; i<points.length; i++) {
                     // skip to the first non-null point and move to it.
                     if (points[i][0] != null && points[i][1] != null) {
                         if (move) {
-                            ctx.moveTo(points[i][0], points[i][1]);
-
-                            // if drawing dashed line and just drawing points, draw one here
-                            if (opts.dashedLine && opts.dashPoints) {
-                                ctx.arc(points[i][0], points[i][1], 2, 0, 2*Math.PI, true);
-                                ctx.fill();
-                                ctx.beginPath();
-                            }
+                            ctxPattern.moveTo(points[i][0], points[i][1]);
                             move = false;
                         }
                         else {
-                            if (opts.dashedLine) {
-
-                                // is spacing such that we're just drawing points?
-                                if (opts.dashPoints) {
-                                    ctx.moveTo(points[i][0], points[i][1]);
-                                    ctx.arc(points[i][0], points[i][1], 2, 0, 2*Math.PI, true);
-                                    ctx.fill();
-                                    ctx.beginPath();
-                                }
-
-                                // do we have part of a dash left over from last interval?
-                                else {
-                                    rise = points[i][1] - points[i-1][1];
-                                    run = points[i][0] - points[i-1][0];
-                                    pl = Math.sqrt(Math.pow(run, 2) + Math.pow(rise, 2));
-                                    ang = Math.atan(rise/run);
-                                    dashx = Math.cos(ang) * opts.dashPattern[0];
-                                    dashy = Math.sin(ang) * opts.dashPattern[0];
-                                    gapx = Math.cos(ang) * opts.dashPattern[1];
-                                    gapy = Math.sin(ang) * opts.dashPattern[1];
-
-                                    if (dashContinuation > 0) {
-                                        if (dashContinuation <= pl) {
-                                            
-                                        }
-                                        else {
-                                            ctx.lineTo(points[i][0], points[i][1]);
-                                            dashContinuation -= pl;
-                                        }
-                                    }
-
-                                    else {
-                                        ndashes = parseInt(pl/dashTotLen);
-                                        x = points[i-1][0];
-                                        y = points[i-1][1];
-
-                                        for (var j=0; j<ndashes; j++) {
-                                            x += dashx;
-                                            y += dashy;
-                                            ctx.lineTo(x, y);
-                                            x += gapx;
-                                            y += gapy;
-                                            ctx.moveTo(x, y);
-                                        }
-                                        
-                                    }
-                                }
-                            }
-                            else {
-                                ctx.lineTo(points[i][0], points[i][1]);
-                            }
+                            ctxPattern.lineTo(points[i][0], points[i][1]);
                         }
                     }
                     else {
                         move = true;
-                        dashContinuation = 0;
                     }
                 }
-                if (closePath) {
-                    ctx.closePath();
-                }
-                if (fill) {
-                    ctx.fill();
-                }
-                else {
-                    ctx.stroke();
-                }
+                
+            }
+            if (closePath) {
+                ctxPattern.closePath();
+            }
+            if (fill) {
+                ctx.fill();
+            }
+            else {
+                ctx.stroke();
             }
         }
         ctx.restore();

File src/jqplot.shapeRenderer.js

View file
     $.jqplot.ShapeRenderer = function(options){
         
         this.lineWidth = 1.5;
+        // prop: linePattern
+        // line pattern 'dashed', 'dotted', 'solid', some combination
+        // of '-' and '.' characters such as '.-.' or a numerical array like 
+        // [draw, skip, draw, skip, ...] such as [1, 10] to draw a dotted line, 
+        // [1, 10, 20, 10] to draw a dot-dash line, and so on.
+        this.linePattern = 'solid';
         // prop: lineJoin
         // How line segments of the shadow are joined.
         this.lineJoin = 'miter';
         var strokeRect = (opts.strokeRect != null) ? opts.strokeRect : this.strokeRect;
         var clearRect = (opts.clearRect != null) ? opts.clearRect : this.clearRect;
         var isarc = (opts.isarc != null) ? opts.isarc : this.isarc;
+        var linePattern = (opts.linePattern != null) ? opts.linePattern : this.linePattern;
+        var ctxPattern = $.jqplot.LinePattern(ctx, linePattern);
         ctx.lineWidth = opts.lineWidth || this.lineWidth;
         ctx.lineJoin = opts.lineJoin || this.lineJoin;
         ctx.lineCap = opts.lineCap || this.lineCap;
         }
         else if (points && points.length){
             var move = true;
-            var l = points.length;
-            var pl;
-            var ang, rise, run, dashx, gapx, dashy, gapy, ndashes, x, y, xstart, ystart, seglen;
-            var xadj = 0, yadj = 0;
-            var dashContinuation = 0;
-            var drawDashes = true;
-            var dashTotLen = 0;
-            if (opts.dashedLine && $.isArray(opts.dashPattern)) {
-                dashTotLen = opts.dashPattern[0] + opts.dashPattern[1]; 
-            }
-            debugger;
-            for (var i=0; i<l; i++) {
+            for (var i=0; i<points.length; i++) {
                 // skip to the first non-null point and move to it.
                 if (points[i][0] != null && points[i][1] != null) {
                     if (move) {
-                        ctx.moveTo(points[i][0], points[i][1]);
-
-                        // if drawing dashed line and just drawing points, draw one here
-                        if (opts.dashedLine && opts.dashPoints) {
-                            ctx.arc(points[i][0], points[i][1], 2, 0, 2*Math.PI, true);
-                            ctx.fill();
-                            ctx.beginPath();
-                        }
+                        ctxPattern.moveTo(points[i][0], points[i][1]);
                         move = false;
                     }
                     else {
-                        if (opts.dashedLine) {
-
-                            // is spacing such that we're just drawing points?
-                            if (opts.dashPoints) {
-                                ctx.moveTo(points[i][0], points[i][1]);
-                                ctx.arc(points[i][0], points[i][1], 2, 0, 2*Math.PI, true);
-                                ctx.fill();
-                                ctx.beginPath();
-                            }
-
-                            // do we have part of a dash left over from last interval?
-                            else {
-                                rise = points[i][1] - points[i-1][1];
-                                run = points[i][0] - points[i-1][0];
-                                pl = Math.sqrt(Math.pow(run, 2) + Math.pow(rise, 2));
-                                ang = Math.atan(rise/run);
-                                dashx = Math.cos(ang) * opts.dashPattern[0];
-                                dashy = Math.sin(ang) * opts.dashPattern[0];
-                                gapx = Math.cos(ang) * opts.dashPattern[1];
-                                gapy = Math.sin(ang) * opts.dashPattern[1];
-                                xadj = dashContinuation * Math.cos(ang);
-                                yadj = dashContinuation * Math.sin(ang);
-                                drawDashes = true;
-                                xstart = points[i-1][0] + xadj;
-                                ystart = points[i-1][1] + yadj;
-                                seglen = pl;
-
-                                if (dashContinuation > 0) {
-                                    if (dashContinuation <= pl) {
-                                        ctx.lineTo(xstart, ystart);
-                                        x = xstart + gapx;
-                                        y = ystart + gapy;
-                                        ctx.moveTo(x, y);
-                                        xstart = x;
-                                        ystart = y;
-                                        seglen = pl - dashContinuation;
-                                    }
-                                    else {
-                                        ctx.lineTo(points[i][0], points[i][1]);
-                                        dashContinuation -= pl;
-                                        drawDashes = false;
-                                    }
-                                }
-
-                                if (drawDashes) {
-                                    ndashes = parseInt(seglen/dashTotLen);
-                                    x = xstart;
-                                    y = ystart;
-
-                                    for (var j=0; j<ndashes; j++) {
-                                        x += dashx;
-                                        y += dashy;
-                                        ctx.lineTo(x, y);
-                                        x += gapx;
-                                        y += gapy;
-                                        ctx.moveTo(x, y);
-                                    }
-
-                                    // If we have more than 1 pixel left over, continue this dash.
-                                    dashContinuation = (seglen - dashTotLen*ndashes > 1) ? seglen - dashTotLen*ndashes : 0;
-                                    
-                                }
-                            }
-                        }
-                        else {
-                            ctx.lineTo(points[i][0], points[i][1]);
-                        }
+                        ctxPattern.lineTo(points[i][0], points[i][1]);
                     }
                 }
                 else {
                     move = true;
-                    dashContinuation = 0;
                 }
             }
             if (closePath) {
-                ctx.closePath();
+                ctxPattern.closePath();
             }
             if (fill) {
                 ctx.fill();

File src/jqplot.themeEngine.js

View file
      * >     series: [{
      * >         color: "#4bb2c5",
      * >         lineWidth: 2.5,
+     * >         linePattern: "solid",
      * >         shadow: true,
      * >         fillColor: "#4bb2c5",
      * >         showMarker: true,
                             plot.series[i].renderer.shapeRenderer.strokeStyle = val;
                             plot.series[i][n] = val;
                         }
-                        else if (n == 'lineWidth') {
-                            plot.series[i].renderer.shapeRenderer.lineWidth = val;
+                        else if ((n == 'lineWidth') || (n == 'linePattern')) {
+                            plot.series[i].renderer.shapeRenderer[n] = val;
                             plot.series[i][n] = val;
                         }
                         else if (n == 'markerOptions') {
     var LineSeriesProperties = function() {
         this.color=null;
         this.lineWidth=null;
+        this.linePattern=null;
         this.shadow=null;
         this.fillColor=null;
         this.showMarker=null;

File src/jquery.jqplot.js

View file
     };
 
 
-    var files = ['jqplot.core.js', 'jqplot.linearTickGenerator.js', 'jqplot.linearAxisRenderer.js', 'jqplot.axisTickRenderer.js', 'jqplot.axisLabelRenderer.js', 'jqplot.tableLegendRenderer.js', 'jqplot.lineRenderer.js', 'jqplot.markerRenderer.js', 'jqplot.divTitleRenderer.js', 'jqplot.canvasGridRenderer.js', 'jqplot.shadowRenderer.js', 'jqplot.shapeRenderer.js', 'jqplot.sprintf.js', 'jsdate.js', 'jqplot.themeEngine.js'];
+    var files = ['jqplot.core.js', 'jqplot.linearTickGenerator.js', 'jqplot.linearAxisRenderer.js', 'jqplot.axisTickRenderer.js', 'jqplot.axisLabelRenderer.js', 'jqplot.tableLegendRenderer.js', 'jqplot.lineRenderer.js', 'jqplot.markerRenderer.js', 'jqplot.divTitleRenderer.js', 'jqplot.canvasGridRenderer.js', 'jqplot.linePattern.js', 'jqplot.shadowRenderer.js', 'jqplot.shapeRenderer.js', 'jqplot.sprintf.js', 'jsdate.js', 'jqplot.themeEngine.js'];
     var rn = getRootNode().root;
     for (var i=0; i<files.length; i++) {
         var pp = rn+files[i];

File src/optionsTutorial.txt

View file
 >        |-series(Array)-|
 >        |               |-Series1-|
 >        |               |         |-lineWidth
+>        |               |         |-linePattern
 >        |               |         |-shadow
 >        |               |         |-showLine
 >        |               |         |-showMarker