src/plugins/legend.js
function generateLegendDashHTML(strokePattern, color, oneEmWidth) {
  // Easy, common case: a solid line
  if (!strokePattern || strokePattern.length <= 1) {
    return `<div class="dygraph-legend-line" style="border-bottom-color: ${color};"></div>`;
  }

  var i, j, paddingLeft, marginRight;
  var strokePixelLength = 0, segmentLoop = 0;
  var normalizedPattern = [];
  var loop;

  // Compute the length of the pixels including the first segment twice, 
  // since we repeat it.
  for (i = 0; i <= strokePattern.length; i++) {
    strokePixelLength += strokePattern[i%strokePattern.length];
  }

  // See if we can loop the pattern by itself at least twice.
  loop = Math.floor(oneEmWidth/(strokePixelLength-strokePattern[0]));
  if (loop > 1) {
    // This pattern fits at least two times, no scaling just convert to em;
    for (i = 0; i < strokePattern.length; i++) {
      normalizedPattern[i] = strokePattern[i]/oneEmWidth;
    }
    // Since we are repeating the pattern, we don't worry about repeating the
    // first segment in one draw.
    segmentLoop = normalizedPattern.length;
  } else {
    // If the pattern doesn't fit in the legend we scale it to fit.
    loop = 1;
    for (i = 0; i < strokePattern.length; i++) {
      normalizedPattern[i] = strokePattern[i]/strokePixelLength;
    }
    // For the scaled patterns we do redraw the first segment.
    segmentLoop = normalizedPattern.length+1;
  }

  // Now make the pattern.
  var dash = "";
  for (j = 0; j < loop; j++) {
    for (i = 0; i < segmentLoop; i+=2) {
      // The padding is the drawn segment.
      paddingLeft = normalizedPattern[i%normalizedPattern.length];
      if (i < strokePattern.length) {
        // The margin is the space segment.
        marginRight = normalizedPattern[(i+1)%normalizedPattern.length];
      } else {
        // The repeated first segment has no right margin.
        marginRight = 0;
      }
      dash += `<div class="dygraph-legend-dash" style="margin-right: ${marginRight}em; padding-left: ${paddingLeft}em;"></div>`;
    }
  }
  return dash;
}
function generateLegendDashHTML(strokePattern, color, oneEmWidth) {
  // Easy, common case: a solid line
  if (!strokePattern || strokePattern.length <= 1) {
    return `<div class="dygraph-legend-line" style="border-bottom-color: ${color};"></div>`;
  }

  var i, j, paddingLeft, marginRight;
  var strokePixelLength = 0, segmentLoop = 0;
  var normalizedPattern = [];
  var loop;

  // Compute the length of the pixels including the first segment twice, 
  // since we repeat it.
  for (i = 0; i <= strokePattern.length; i++) {
    strokePixelLength += strokePattern[i%strokePattern.length];
  }

  // See if we can loop the pattern by itself at least twice.
  loop = Math.floor(oneEmWidth/(strokePixelLength-strokePattern[0]));
  if (loop > 1) {
    // This pattern fits at least two times, no scaling just convert to em;
    for (i = 0; i < strokePattern.length; i++) {
      normalizedPattern[i] = strokePattern[i]/oneEmWidth;
    }
    // Since we are repeating the pattern, we don't worry about repeating the
    // first segment in one draw.
    segmentLoop = normalizedPattern.length;
  } else {
    // If the pattern doesn't fit in the legend we scale it to fit.
    loop = 1;
    for (i = 0; i < strokePattern.length; i++) {
      normalizedPattern[i] = strokePattern[i]/strokePixelLength;
    }
    // For the scaled patterns we do redraw the first segment.
    segmentLoop = normalizedPattern.length+1;
  }

  // Now make the pattern.
  var dash = "";
  for (j = 0; j < loop; j++) {
    for (i = 0; i < segmentLoop; i+=2) {
      // The padding is the drawn segment.
      paddingLeft = normalizedPattern[i%normalizedPattern.length];
      if (i < strokePattern.length) {
        // The margin is the space segment.
        marginRight = normalizedPattern[(i+1)%normalizedPattern.length];
      } else {
        // The repeated first segment has no right margin.
        marginRight = 0;
      }
      dash += `<div class="dygraph-legend-dash" style="margin-right: ${marginRight}em; padding-left: ${paddingLeft}em;"></div>`;
    }
  }
  return dash;
}
function generateLegendDashHTML ( strokePattern , color , oneEmWidth ) { // Easy, common case: a solid line if ( ! strokePattern || strokePattern . length <= 1 ) { return ` ${ color } ` ; } var i , j , paddingLeft , marginRight ; var strokePixelLength = 0 , segmentLoop = 0 ; var normalizedPattern = [ ] ; var loop ; // Compute the length of the pixels including the first segment twice,  // since we repeat it. for ( i = 0 ; i <= strokePattern . length ; i ++ ) { strokePixelLength += strokePattern [ i % strokePattern . length ] ; } // See if we can loop the pattern by itself at least twice. loop = Math . floor ( oneEmWidth / ( strokePixelLength - strokePattern [ 0 ] ) ) ; if ( loop > 1 ) { // This pattern fits at least two times, no scaling just convert to em; for ( i = 0 ; i < strokePattern . length ; i ++ ) { normalizedPattern [ i ] = strokePattern [ i ] / oneEmWidth ; } // Since we are repeating the pattern, we don't worry about repeating the // first segment in one draw. segmentLoop = normalizedPattern . length ; } else { // If the pattern doesn't fit in the legend we scale it to fit. loop = 1 ; for ( i = 0 ; i < strokePattern . length ; i ++ ) { normalizedPattern [ i ] = strokePattern [ i ] / strokePixelLength ; } // For the scaled patterns we do redraw the first segment. segmentLoop = normalizedPattern . length + 1 ; } // Now make the pattern. var dash = "" ; for ( j = 0 ; j < loop ; j ++ ) { for ( i = 0 ; i < segmentLoop ; i += 2 ) { // The padding is the drawn segment. paddingLeft = normalizedPattern [ i % normalizedPattern . length ] ; if ( i < strokePattern . length ) { // The margin is the space segment. marginRight = normalizedPattern [ ( i + 1 ) % normalizedPattern . length ] ; } else { // The repeated first segment has no right margin. marginRight = 0 ; } dash += ` ${ marginRight } ${ paddingLeft } ` ; } } return dash ; }
Generates html for the "dash" displayed on the legend when using "legend: always".
In particular, this works for dashed lines with any stroke pattern. It will
try to scale the pattern to fit in 1em width. Or if small enough repeat the
pattern for 1em width.

@param strokePattern The pattern
@param color The color of the series.
@param oneEmWidth The width in pixels of 1em in the legend.
@private
 TODO(danvk): cache the results of this
Generates html for the dash displayed on the legend when using legend : always . In particular this works for dashed lines with any stroke pattern . It will try to scale the pattern to fit in 1em width . Or if small enough repeat the pattern for 1em width .