动态验证码实现思路

转自:http://fex.baidu.com/blog/2014/07/captcha-gif/
<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <style>
canvas {
  border: black 1px solid;
}
  </style>
  <script src="../library/gif.js"></script>
</head>
<body>
  <div>
    Key: <input type="text" maxlength="8" /> <input type="button" value="build" />
  </div>
  <canvas width="300" height="70"></canvas>
  <img width="300" height="70" /><a download="captcha.gif">download...</a>
  <script>

/**
 * 绘制旋转的文字
 * @param {CanvasRenderingContext2D} context 上下文
 * @param {String} text 文本
 * @param {Number} x 中心坐标 x
 * @param {Number} y 中心坐标 y
 * @param {Number} angle 角度,单位弧度
 */
function rotateText(context, text, x, y, angle) {
  if (!context) {
    return;
  }

  context.save(); // 保存上次的风格设置
  context.textAlign = 'center'; // 横向居中
  context.textBaseline = 'middle'; // 纵向居中
  context.translate(x, y); // 修改坐标系原点
  context.rotate(angle); // 旋转
  context.strokeText(text, 0, 0); // 绘制文本
  context.restore(); // 恢复上次的风格设置
}

/**
 * 随机字符串
 * @param{String} chars 字符串
 * @param{Number} len 长度
 */
function randomText(chars, len) {
  var result = '';
  for (var i = 0; i < len; i++) {
    result += chars.charAt(parseInt(chars.length * Math.random()));
  }
  return result;
}

void function() {
  // @see http://www.w3.org/TR/2dcontext/
  var canvas = document.querySelector('canvas');
  var context = canvas.getContext('2d');

  context.font = '30px Verdana'; // 字体大小和字体名

  var lineHeight = 15; // 行高
  var backLength = 3;
  var backTexts = {};
  var backXOffsets = {};
  var keyYOffsets = {};
  var keyAOffsets = {};
  var backSpeed = 10000 + parseInt(100 * Math.random());
  var keySpeed = 12000 + parseInt(100 * Math.random());
  var key = '';
  
  function init(value) {
    key = String(value).toUpperCase();
    // 随机备件
    for (var i = 0; i < canvas.height / lineHeight; i++) {
      backTexts[i] = randomText('ABCDEFGHIJKLMNOPQRST0123456789', backLength);
      backXOffsets[i] = Math.random() * canvas.width;
    }
    for (var i = 0; i < key.length; i++) {
      keyYOffsets[i] = Math.random() * lineHeight / 2;
      keyAOffsets[i] = 0.05 - Math.random() * 0.1;
    }
  }

  function renderBack(now, context, text, y, xOffset) {
    var tick = now % backSpeed;
    for (var i = 0; i < backLength; i++) {
      var t = (xOffset + (tick / backSpeed) * canvas.width + 
        (canvas.width / backLength) * i) % canvas.width;
      rotateText(context, text[i], t, y,
          i / backLength * Math.PI * 2 + (tick / backSpeed) * Math.PI * 2);
    }
  }

  function render(now, context) {
    context.fillStyle = '#FFFFFF';
    context.fillRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = '#000000';

    // 绘制背景文字
    for (var i = 0; i < canvas.height / lineHeight; i++) {
      renderBack(now, context, backTexts[i], lineHeight * i, backXOffsets[i]);
    }

    // 绘制 key
    var tick = now % keySpeed;
    var keyCharWidth = canvas.width / key.length;
    for (var i = 0; i < key.length; i++) {
      var tx = keyCharWidth + (((canvas.width - keyCharWidth) / key.length) * i) % canvas.width;
      var ty = Math.cos(now / 1000) * Math.PI * keyYOffsets[i];
      rotateText(context, key[i], tx,
        canvas.height / 2 - ty, Math.cos(now / 1000) * Math.PI * 0.1 + keyAOffsets[i]);
    }
  }
  init('zswang');
  setInterval(function() {
    render(Number(new Date), context);
  }, 100);


  document.querySelector('input[type=text]').addEventListener('input', function() {
    init(this.value);
  });

  document.querySelector('input[type=button]').addEventListener('click', function() {
    var self = this;
    self.disabled = true;
    var gif = new GIF({
      repeat: 0,
      workers: 2,
      quality: 10,
      workerScript: '../library/gif.worker.js'
    });

    var canvasTemp = document.createElement('canvas');
    canvasTemp.width = canvas.width;
    canvasTemp.height = canvas.height;
    var context = canvasTemp.getContext('2d');
    context.font = '30px Verdana'; // 字体大小和字体名
    context.textAlign = 'center';
    for (var i = 0; i < 5000; i += 100) {
      render(i, context);
      gif.addFrame(canvasTemp, { delay: 100, copy: true });
    }
    gif.on('finished', function(blob) {
      var url = URL.createObjectURL(blob);
      document.querySelector('img').src = url;
      document.querySelector('a').href = url;
      self.disabled = false;
    });
    gif.render();
  });
}();
  </script>
</body>
</html>
<!doctype html><html><head> <meta charset="utf-8" /> <style>canvas { border: black 1px solid;} </style> <script src="../library/gif.js"></script></head><body> <div> Key: <input type="text" maxlength="8" /> <input type="button" value="build" /> </div> <canvas width="300" height="70"></canvas> <img width="300" height="70" /><a download="captcha.gif">download...</a> <script>/** * 绘制旋转的文字 * @param {CanvasRenderingContext2D} context 上下文 * @param {String} text 文本 * @param {Number} x 中心坐标 x * @param {Number} y 中心坐标 y * @param {Number} angle 角度,单位弧度 */function rotateText(context, text, x, y, angle) { if (!context) { return; } context.save(); // 保存上次的风格设置 context.textAlign = 'center'; // 横向居中 context.textBaseline = 'middle'; // 纵向居中 context.translate(x, y); // 修改坐标系原点 context.rotate(angle); // 旋转 context.strokeText(text, 0, 0); // 绘制文本 context.restore(); // 恢复上次的风格设置}/** * 随机字符串 * @param{String} chars 字符串 * @param{Number} len 长度 */function randomText(chars, len) { var result = ''; for (var i = 0; i < len; i++) { result += chars.charAt(parseInt(chars.length * Math.random())); } return result;}void function() { // @see http://www.w3.org/TR/2dcontext/ var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); context.font = '30px Verdana'; // 字体大小和字体名 var lineHeight = 15; // 行高 var backLength = 3; var backTexts = {}; var backXOffsets = {}; var keyYOffsets = {}; var keyAOffsets = {}; var backSpeed = 10000 + parseInt(100 * Math.random()); var keySpeed = 12000 + parseInt(100 * Math.random()); var key = ''; function init(value) { key = String(value).toUpperCase(); // 随机备件 for (var i = 0; i < canvas.height / lineHeight; i++) { backTexts[i] = randomText('ABCDEFGHIJKLMNOPQRST0123456789', backLength); backXOffsets[i] = Math.random() * canvas.width; } for (var i = 0; i < key.length; i++) { keyYOffsets[i] = Math.random() * lineHeight / 2; keyAOffsets[i] = 0.05 - Math.random() * 0.1; } } function renderBack(now, context, text, y, xOffset) { var tick = now % backSpeed; for (var i = 0; i < backLength; i++) { var t = (xOffset + (tick / backSpeed) * canvas.width + (canvas.width / backLength) * i) % canvas.width; rotateText(context, text[i], t, y, i / backLength * Math.PI * 2 + (tick / backSpeed) * Math.PI * 2); } } function render(now, context) { context.fillStyle = '#FFFFFF'; context.fillRect(0, 0, canvas.width, canvas.height); context.fillStyle = '#000000'; // 绘制背景文字 for (var i = 0; i < canvas.height / lineHeight; i++) { renderBack(now, context, backTexts[i], lineHeight * i, backXOffsets[i]); } // 绘制 key var tick = now % keySpeed; var keyCharWidth = canvas.width / key.length; for (var i = 0; i < key.length; i++) { var tx = keyCharWidth + (((canvas.width - keyCharWidth) / key.length) * i) % canvas.width; var ty = Math.cos(now / 1000) * Math.PI * keyYOffsets[i]; rotateText(context, key[i], tx, canvas.height / 2 - ty, Math.cos(now / 1000) * Math.PI * 0.1 + keyAOffsets[i]); } } init('zswang'); setInterval(function() { render(Number(new Date), context); }, 100); document.querySelector('input[type=text]').addEventListener('input', function() { init(this.value); }); document.querySelector('input[type=button]').addEventListener('click', function() { var self = this; self.disabled = true; var gif = new GIF({ repeat: 0, workers: 2, quality: 10, workerScript: '../library/gif.worker.js' }); var canvasTemp = document.createElement('canvas'); canvasTemp.width = canvas.width; canvasTemp.height = canvas.height; var context = canvasTemp.getContext('2d'); context.font = '30px Verdana'; // 字体大小和字体名 context.textAlign = 'center'; for (var i = 0; i < 5000; i += 100) { render(i, context); gif.addFrame(canvasTemp, { delay: 100, copy: true }); } gif.on('finished', function(blob) { var url = URL.createObjectURL(blob); document.querySelector('img').src = url; document.querySelector('a').href = url; self.disabled = false; }); gif.render(); });}(); </script></body></html>



<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <style>
canvas {
  border: black 1px solid;
}
  </style>
  <script src="../library/gif.js"></script>
</head>
<body>
  <div>
    Key: <input type="text" maxlength="8" /> <input type="button" value="build" />
  </div>
  <canvas width="300" height="70"></canvas>
  <img width="300" height="70" /><a download="captcha.gif">download...</a>
  <script>

/**
 * 绘制旋转的文字
 * @param {CanvasRenderingContext2D} context 上下文
 * @param {String} text 文本
 * @param {Number} x 中心坐标 x
 * @param {Number} y 中心坐标 y
 * @param {Number} angle 角度,单位弧度
 */
function rotateText(context, text, x, y, angle) {
  if (!context) {
    return;
  }

  context.save(); // 保存上次的风格设置
  context.textAlign = 'center'; // 横向居中
  context.textBaseline = 'middle'; // 纵向居中
  context.translate(x, y); // 修改坐标系原点
  context.rotate(angle); // 旋转
  context.strokeText(text, 0, 0); // 绘制文本
  context.restore(); // 恢复上次的风格设置
}

/**
 * 随机字符串
 * @param{String} chars 字符串
 * @param{Number} len 长度
 */
function randomText(chars, len) {
  var result = '';
  for (var i = 0; i < len; i++) {
    result += chars.charAt(parseInt(chars.length * Math.random()));
  }
  return result;
}

void function() {
  // @see http://www.w3.org/TR/2dcontext/
  var canvas = document.querySelector('canvas');
  var context = canvas.getContext('2d');

  context.font = '30px Verdana'; // 字体大小和字体名

  var lineHeight = 15; // 行高
  var backLength = 3;
  var backTexts = {};
  var backXOffsets = {};
  var keyYOffsets = {};
  var keyAOffsets = {};
  var backSpeed = 10000 + parseInt(100 * Math.random());
  var keySpeed = 12000 + parseInt(100 * Math.random());
  var key = '';
  
  function init(value) {
    key = String(value).toUpperCase();
    // 随机备件
    for (var i = 0; i < canvas.height / lineHeight; i++) {
      backTexts[i] = randomText('ABCDEFGHIJKLMNOPQRST0123456789', backLength);
      backXOffsets[i] = Math.random() * canvas.width;
    }
    for (var i = 0; i < key.length; i++) {
      keyYOffsets[i] = Math.random() * lineHeight / 2;
      keyAOffsets[i] = 0.05 - Math.random() * 0.1;
    }
  }

  function renderBack(now, context, text, y, xOffset) {
    var tick = now % backSpeed;
    for (var i = 0; i < backLength; i++) {
      var t = (xOffset + (tick / backSpeed) * canvas.width + 
        (canvas.width / backLength) * i) % canvas.width;
      rotateText(context, text[i], t, y,
          i / backLength * Math.PI * 2 + (tick / backSpeed) * Math.PI * 2);
    }
  }

  function render(now, context) {
    context.fillStyle = '#FFFFFF';
    context.fillRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = '#000000';

    // 绘制背景文字
    for (var i = 0; i < canvas.height / lineHeight; i++) {
      renderBack(now, context, backTexts[i], lineHeight * i, backXOffsets[i]);
    }

    // 绘制 key
    var tick = now % keySpeed;
    var keyCharWidth = canvas.width / key.length;
    for (var i = 0; i < key.length; i++) {
      var tx = keyCharWidth + (((canvas.width - keyCharWidth) / key.length) * i) % canvas.width;
      var ty = Math.cos(now / 1000) * Math.PI * keyYOffsets[i];
      rotateText(context, key[i], tx,
        canvas.height / 2 - ty, Math.cos(now / 1000) * Math.PI * 0.1 + keyAOffsets[i]);
    }
  }
  init('zswang');
  setInterval(function() {
    render(Number(new Date), context);
  }, 100);


  document.querySelector('input[type=text]').addEventListener('input', function() {
    init(this.value);
  });

  document.querySelector('input[type=button]').addEventListener('click', function() {
    var self = this;
    self.disabled = true;
    var gif = new GIF({
      repeat: 0,
      workers: 2,
      quality: 10,
      workerScript: '../library/gif.worker.js'
    });

    var canvasTemp = document.createElement('canvas');
    canvasTemp.width = canvas.width;
    canvasTemp.height = canvas.height;
    var context = canvasTemp.getContext('2d');
    context.font = '30px Verdana'; // 字体大小和字体名
    context.textAlign = 'center';
    for (var i = 0; i < 5000; i += 100) {
      render(i, context);
      gif.addFrame(canvasTemp, { delay: 100, copy: true });
    }
    gif.on('finished', function(blob) {
      var url = URL.createObjectURL(blob);
      document.querySelector('img').src = url;
      document.querySelector('a').href = url;
      self.disabled = false;
    });
    gif.render();
  });
}();
  </script>
</body>
</html>


<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <style>
canvas {
  border: black 1px solid;
}
  </style>
  <script src="../library/gif.js"></script>
</head>
<body>
  <div>
    Key: <input type="text" maxlength="8" /> <input type="button" value="build" />
  </div>
  <canvas width="300" height="70"></canvas>
  <img width="300" height="70" /><a download="captcha.gif">download...</a>
  <script>

/**
 * 绘制旋转的文字
 * @param {CanvasRenderingContext2D} context 上下文
 * @param {String} text 文本
 * @param {Number} x 中心坐标 x
 * @param {Number} y 中心坐标 y
 * @param {Number} angle 角度,单位弧度
 */
function rotateText(context, text, x, y, angle) {
  if (!context) {
    return;
  }

  context.save(); // 保存上次的风格设置
  context.textAlign = 'center'; // 横向居中
  context.textBaseline = 'middle'; // 纵向居中
  context.translate(x, y); // 修改坐标系原点
  context.rotate(angle); // 旋转
  context.strokeText(text, 0, 0); // 绘制文本
  context.restore(); // 恢复上次的风格设置
}

/**
 * 随机字符串
 * @param{String} chars 字符串
 * @param{Number} len 长度
 */
function randomText(chars, len) {
  var result = '';
  for (var i = 0; i < len; i++) {
    result += chars.charAt(parseInt(chars.length * Math.random()));
  }
  return result;
}

void function() {
  // @see http://www.w3.org/TR/2dcontext/
  var canvas = document.querySelector('canvas');
  var context = canvas.getContext('2d');

  context.font = '30px Verdana'; // 字体大小和字体名

  var lineHeight = 15; // 行高
  var backLength = 3;
  var backTexts = {};
  var backXOffsets = {};
  var keyYOffsets = {};
  var keyAOffsets = {};
  var backSpeed = 10000 + parseInt(100 * Math.random());
  var keySpeed = 12000 + parseInt(100 * Math.random());
  var key = '';
  
  function init(value) {
    key = String(value).toUpperCase();
    // 随机备件
    for (var i = 0; i < canvas.height / lineHeight; i++) {
      backTexts[i] = randomText('ABCDEFGHIJKLMNOPQRST0123456789', backLength);
      backXOffsets[i] = Math.random() * canvas.width;
    }
    for (var i = 0; i < key.length; i++) {
      keyYOffsets[i] = Math.random() * lineHeight / 2;
      keyAOffsets[i] = 0.05 - Math.random() * 0.1;
    }
  }

  function renderBack(now, context, text, y, xOffset) {
    var tick = now % backSpeed;
    for (var i = 0; i < backLength; i++) {
      var t = (xOffset + (tick / backSpeed) * canvas.width + 
        (canvas.width / backLength) * i) % canvas.width;
      rotateText(context, text[i], t, y,
          i / backLength * Math.PI * 2 + (tick / backSpeed) * Math.PI * 2);
    }
  }

  function render(now, context) {
    context.fillStyle = '#FFFFFF';
    context.fillRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = '#000000';

    // 绘制背景文字
    for (var i = 0; i < canvas.height / lineHeight; i++) {
      renderBack(now, context, backTexts[i], lineHeight * i, backXOffsets[i]);
    }

    // 绘制 key
    var tick = now % keySpeed;
    var keyCharWidth = canvas.width / key.length;
    for (var i = 0; i < key.length; i++) {
      var tx = keyCharWidth + (((canvas.width - keyCharWidth) / key.length) * i) % canvas.width;
      var ty = Math.cos(now / 1000) * Math.PI * keyYOffsets[i];
      rotateText(context, key[i], tx,
        canvas.height / 2 - ty, Math.cos(now / 1000) * Math.PI * 0.1 + keyAOffsets[i]);
    }
  }
  init('zswang');
  setInterval(function() {
    render(Number(new Date), context);
  }, 100);


  document.querySelector('input[type=text]').addEventListener('input', function() {
    init(this.value);
  });

  document.querySelector('input[type=button]').addEventListener('click', function() {
    var self = this;
    self.disabled = true;
    var gif = new GIF({
      repeat: 0,
      workers: 2,
      quality: 10,
      workerScript: '../library/gif.worker.js'
    });

    var canvasTemp = document.createElement('canvas');
    canvasTemp.width = canvas.width;
    canvasTemp.height = canvas.height;
    var context = canvasTemp.getContext('2d');
    context.font = '30px Verdana'; // 字体大小和字体名
    context.textAlign = 'center';
    for (var i = 0; i < 5000; i += 100) {
      render(i, context);
      gif.addFrame(canvasTemp, { delay: 100, copy: true });
    }
    gif.on('finished', function(blob) {
      var url = URL.createObjectURL(blob);
      document.querySelector('img').src = url;
      document.querySelector('a').href = url;
      self.disabled = false;
    });
    gif.render();
  });
}();
  </script>
</body>
</html>
<!doctype html><html><head> <meta charset="utf-8" /> <style>canvas { border: black 1px solid;} </style> <script src="../library/gif.js"></script></head><body> <div> Key: <input type="text" maxlength="8" /> <input type="button" value="build" /> </div> <canvas width="300" height="70"></canvas> <img width="300" height="70" /><a download="captcha.gif">download...</a> <script>/** * 绘制旋转的文字 * @param {CanvasRenderingContext2D} context 上下文 * @param {String} text 文本 * @param {Number} x 中心坐标 x * @param {Number} y 中心坐标 y * @param {Number} angle 角度,单位弧度 */function rotateText(context, text, x, y, angle) { if (!context) { return; } context.save(); // 保存上次的风格设置 context.textAlign = 'center'; // 横向居中 context.textBaseline = 'middle'; // 纵向居中 context.translate(x, y); // 修改坐标系原点 context.rotate(angle); // 旋转 context.strokeText(text, 0, 0); // 绘制文本 context.restore(); // 恢复上次的风格设置}/** * 随机字符串 * @param{String} chars 字符串 * @param{Number} len 长度 */function randomText(chars, len) { var result = ''; for (var i = 0; i < len; i++) { result += chars.charAt(parseInt(chars.length * Math.random())); } return result;}void function() { // @see http://www.w3.org/TR/2dcontext/ var canvas = document.querySelector('canvas'); var context = canvas.getContext('2d'); context.font = '30px Verdana'; // 字体大小和字体名 var lineHeight = 15; // 行高 var backLength = 3; var backTexts = {}; var backXOffsets = {}; var keyYOffsets = {}; var keyAOffsets = {}; var backSpeed = 10000 + parseInt(100 * Math.random()); var keySpeed = 12000 + parseInt(100 * Math.random()); var key = ''; function init(value) { key = String(value).toUpperCase(); // 随机备件 for (var i = 0; i < canvas.height / lineHeight; i++) { backTexts[i] = randomText('ABCDEFGHIJKLMNOPQRST0123456789', backLength); backXOffsets[i] = Math.random() * canvas.width; } for (var i = 0; i < key.length; i++) { keyYOffsets[i] = Math.random() * lineHeight / 2; keyAOffsets[i] = 0.05 - Math.random() * 0.1; } } function renderBack(now, context, text, y, xOffset) { var tick = now % backSpeed; for (var i = 0; i < backLength; i++) { var t = (xOffset + (tick / backSpeed) * canvas.width + (canvas.width / backLength) * i) % canvas.width; rotateText(context, text[i], t, y, i / backLength * Math.PI * 2 + (tick / backSpeed) * Math.PI * 2); } } function render(now, context) { context.fillStyle = '#FFFFFF'; context.fillRect(0, 0, canvas.width, canvas.height); context.fillStyle = '#000000'; // 绘制背景文字 for (var i = 0; i < canvas.height / lineHeight; i++) { renderBack(now, context, backTexts[i], lineHeight * i, backXOffsets[i]); } // 绘制 key var tick = now % keySpeed; var keyCharWidth = canvas.width / key.length; for (var i = 0; i < key.length; i++) { var tx = keyCharWidth + (((canvas.width - keyCharWidth) / key.length) * i) % canvas.width; var ty = Math.cos(now / 1000) * Math.PI * keyYOffsets[i]; rotateText(context, key[i], tx, canvas.height / 2 - ty, Math.cos(now / 1000) * Math.PI * 0.1 + keyAOffsets[i]); } } init('zswang'); setInterval(function() { render(Number(new Date), context); }, 100); document.querySelector('input[type=text]').addEventListener('input', function() { init(this.value); }); document.querySelector('input[type=button]').addEventListener('click', function() { var self = this; self.disabled = true; var gif = new GIF({ repeat: 0, workers: 2, quality: 10, workerScript: '../library/gif.worker.js' }); var canvasTemp = document.createElement('canvas'); canvasTemp.width = canvas.width; canvasTemp.height = canvas.height; var context = canvasTemp.getContext('2d'); context.font = '30px Verdana'; // 字体大小和字体名 context.textAlign = 'center'; for (var i = 0; i < 5000; i += 100) { render(i, context); gif.addFrame(canvasTemp, { delay: 100, copy: true }); } gif.on('finished', function(blob) { var url = URL.createObjectURL(blob); document.querySelector('img').src = url; document.querySelector('a').href = url; self.disabled = false; }); gif.render(); });}(); </script></body></html>
<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <style>
canvas {
  border: black 1px solid;
}
  </style>
  <script src="../library/gif.js"></script>
</head>
<body>
  <div>
    Key: <input type="text" maxlength="8" /> <input type="button" value="build" />
  </div>
  <canvas width="300" height="70"></canvas>
  <img width="300" height="70" /><a download="captcha.gif">download...</a>
  <script>

/**
 * 绘制旋转的文字
 * @param {CanvasRenderingContext2D} context 上下文
 * @param {String} text 文本
 * @param {Number} x 中心坐标 x
 * @param {Number} y 中心坐标 y
 * @param {Number} angle 角度,单位弧度
 */
function rotateText(context, text, x, y, angle) {
  if (!context) {
    return;
  }

  context.save(); // 保存上次的风格设置
  context.textAlign = 'center'; // 横向居中
  context.textBaseline = 'middle'; // 纵向居中
  context.translate(x, y); // 修改坐标系原点
  context.rotate(angle); // 旋转
  context.strokeText(text, 0, 0); // 绘制文本
  context.restore(); // 恢复上次的风格设置
}

/**
 * 随机字符串
 * @param{String} chars 字符串
 * @param{Number} len 长度
 */
function randomText(chars, len) {
  var result = '';
  for (var i = 0; i < len; i++) {
    result += chars.charAt(parseInt(chars.length * Math.random()));
  }
  return result;
}

void function() {
  // @see http://www.w3.org/TR/2dcontext/
  var canvas = document.querySelector('canvas');
  var context = canvas.getContext('2d');

  context.font = '30px Verdana'; // 字体大小和字体名

  var lineHeight = 15; // 行高
  var backLength = 3;
  var backTexts = {};
  var backXOffsets = {};
  var keyYOffsets = {};
  var keyAOffsets = {};
  var backSpeed = 10000 + parseInt(100 * Math.random());
  var keySpeed = 12000 + parseInt(100 * Math.random());
  var key = '';
  
  function init(value) {
    key = String(value).toUpperCase();
    // 随机备件
    for (var i = 0; i < canvas.height / lineHeight; i++) {
      backTexts[i] = randomText('ABCDEFGHIJKLMNOPQRST0123456789', backLength);
      backXOffsets[i] = Math.random() * canvas.width;
    }
    for (var i = 0; i < key.length; i++) {
      keyYOffsets[i] = Math.random() * lineHeight / 2;
      keyAOffsets[i] = 0.05 - Math.random() * 0.1;
    }
  }

  function renderBack(now, context, text, y, xOffset) {
    var tick = now % backSpeed;
    for (var i = 0; i < backLength; i++) {
      var t = (xOffset + (tick / backSpeed) * canvas.width + 
        (canvas.width / backLength) * i) % canvas.width;
      rotateText(context, text[i], t, y,
          i / backLength * Math.PI * 2 + (tick / backSpeed) * Math.PI * 2);
    }
  }

  function render(now, context) {
    context.fillStyle = '#FFFFFF';
    context.fillRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = '#000000';

    // 绘制背景文字
    for (var i = 0; i < canvas.height / lineHeight; i++) {
      renderBack(now, context, backTexts[i], lineHeight * i, backXOffsets[i]);
    }

    // 绘制 key
    var tick = now % keySpeed;
    var keyCharWidth = canvas.width / key.length;
    for (var i = 0; i < key.length; i++) {
      var tx = keyCharWidth + (((canvas.width - keyCharWidth) / key.length) * i) % canvas.width;
      var ty = Math.cos(now / 1000) * Math.PI * keyYOffsets[i];
      rotateText(context, key[i], tx,
        canvas.height / 2 - ty, Math.cos(now / 1000) * Math.PI * 0.1 + keyAOffsets[i]);
    }
  }
  init('zswang');
  setInterval(function() {
    render(Number(new Date), context);
  }, 100);


  document.querySelector('input[type=text]').addEventListener('input', function() {
    init(this.value);
  });

  document.querySelector('input[type=button]').addEventListener('click', function() {
    var self = this;
    self.disabled = true;
    var gif = new GIF({
      repeat: 0,
      workers: 2,
      quality: 10,
      workerScript: '../library/gif.worker.js'
    });

    var canvasTemp = document.createElement('canvas');
    canvasTemp.width = canvas.width;
    canvasTemp.height = canvas.height;
    var context = canvasTemp.getContext('2d');
    context.font = '30px Verdana'; // 字体大小和字体名
    context.textAlign = 'center';
    for (var i = 0; i < 5000; i += 100) {
      render(i, context);
      gif.addFrame(canvasTemp, { delay: 100, copy: true });
    }
    gif.on('finished', function(blob) {
      var url = URL.createObjectURL(blob);
      document.querySelector('img').src = url;
      document.querySelector('a').href = url;
      self.disabled = false;
    });
    gif.render();
  });
}();
  </script>
</body>
</html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值