×

新玩法:将DOM对象转换成图片

作者:andy0012018.03.16来源:Web前端之家浏览:19972评论:0
关键词:DOMSVGcanvas

有一种新玩法:将DOM对象转换成图片,很神奇,很神奇,很神奇!

我们要做的,就是将DOM的内容原原本本复制,并绘制成图片。svg的foreignObject元素可以包含html片段,这样就可以将整个DOM片段转换成svg。
然后我们可以有两个选择,第一是将svg插入到一个div中,或者将svg绘制到canvas。svg相对于canvas来说,更清晰。废话少说,上代码:

<html>
<body>
<script>
// dom
  const div = document.createElement('div');
  div.innerHTML = `<div>
  <h4>svg:</h4>
  <div id="svg"></div>
</div>
<div>
  <h4>canvas:</h4>
  <canvas id="canvas" style="width: 200px; height: 200px; zoom: .5;" width="100" height="100"></canvas>
</div>`;
  document.body.appendChild(div);
  // 图片
  const html = `<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
  <foreignObject width="100%" height="100%">
    <div xmlns="http://www.w3.org/1999/xhtml">Hello, world!</div>
  </foreignObject>
</svg>`;
  document.getElementById('svg').innerHTML = html;
  const img = new Image();
  const svg = new Blob(html.split(''), {
    type: 'image/svg+xml;charset=utf-8'
  });
  const url = window.URL.createObjectURL(svg);
  function imgLoad(event){
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0);
    ctx.scale(2, 2);
    window.URL.revokeObjectURL(url);
  }
  img.src = url;
  img.addEventListener('load', imgLoad, false);
</script>
</body></html>

不过要注意的是,在svg里面的class是无效的,样式只有style=“key: value;”才能生效。可以使用window.getComputedStyle来获取DOM的样式。如果嫌麻烦,还可以使用html2canvas库。
svg内dom节点的xmlns属性不能省略。

最后来个简单canvas的Demo:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    body { margin: 0; }
    .article { box-sizing: border-box; margin: 0 auto; padding: 10px; width: 300px; height: 560px; border: 1px solid #ddd; border-radius: 5px; background-color: #fff; }
    .article-title { font-size: 16px; }
    .article-secondtitle { font-size: 12px; color: #7e7e7e; }
    .article-title, .article-secondtitle { text-align: center; }
    .article p { font-size: 14px; }
    .canvas { position: fixed; top: 0; left: 50%; display: block; width: 300px; height: 560px; margin: 0 0 0 -152px; border: 1px solid #ddd; border-radius: 5px; }

    @keyframes body1{
      0% { transform: rotateZ(0) rotateY(0) scale(1) ; }
      50% { transform: rotateZ(180deg) rotateY(0) scale(.9) ; }
      100% { transform: rotateZ(360deg) rotateY(180deg) scale(0); }
    }
    .animate {
      animation-name: body1;
      animation-timing-function: linear;
      animation-fill-mode: forwards;
    }
    .ani0 { animation-delay: 1s; animation-duration: 2s; z-index: 4; }
    .ani1 { animation-delay: 1.4s; animation-duration: 1.7s; z-index: 3; }
    .ani2 { animation-delay: 1.8s; animation-duration: 1.4s; z-index: 2; }
    .ani3 { animation-delay: 2.2s; animation-duration: 1.1s; z-index: 1; }
  </style>
</head>
<body>
<article class="article" id="article">
  <h1 class="article-title">将进酒·君不见黄河之水天上来</h1>
    <h6 class="article-secondtitle">[唐] 李白</h6>
  <p>君不见黄河之水天上来,奔流到海不复回。</p>
  <p>君不见高堂明镜悲白发,朝如青丝暮成雪。</p>
  <p>人生得意须尽欢,莫使金樽空对月。</p>
  <p>天生我材必有用,千金散尽还复来。</p>
  <p>烹羊宰牛且为乐,会须一饮三百杯。</p>
  <p>岑夫子,丹丘生,将进酒,杯莫停。</p>
  <p>与君歌一曲,请君为我侧耳听。</p>
  <p>钟鼓馔玉不足贵,但愿长醉不复醒。</p>
  <p>古来圣贤皆寂寞,惟有饮者留其名。</p>
  <p>陈王昔时宴平乐,斗酒十千恣欢谑。</p>
  <p>主人何为言少钱,径须沽取对君酌。</p>
  <p>五花马,千金裘,</p>
  <p>呼儿将出换美酒,与尔同销万古愁。</p>
</article>
<canvas class="canvas animate ani0" id="canvas_0" width="300" height="560"></canvas>
<canvas class="canvas animate ani1" id="canvas_1" width="300" height="560"></canvas>
<canvas class="canvas animate ani2" id="canvas_2" width="300" height="560"></canvas>
<canvas class="canvas animate ani3" id="canvas_3" width="300" height="560"></canvas>
<!-- 特效代码 -->
<script>

  function style2String(node){
    const css = window.getComputedStyle(node);
    let style = '';
    style += `padding: ${ css.padding }; `;
    style += `width: ${ css.width }; `;
    style += `font-size: ${ css.fontSize }; `;
    style += `font-family: ${ css.fontFamily.replace(/"/g, '') }; `;
    style += `border-radius: ${ css.borderRadius }; `;
    style += `color: ${ css.color }; `;
    style += `text-align: ${ css.textAlign }; `;
    style += `background-color: ${ css.backgroundColor }; `;
    return style;
  }

  function html2Text(node){
    // 节点
    let txt = '';
    if(node.nodeName !== '#text'){
      const nodeName = node.nodeName.toLowerCase();
      const style = style2String(node);
      txt += `<${ nodeName } style="${ style }">`;
      // 子节点
      const childNodes = node.childNodes;
      for(let i = 0, j = childNodes.length; i < j; i++){
        txt += html2Text(childNodes[i]);
      }
      txt += `</${ nodeName }>`;
    }else{
      txt += node.data;
    }
    return txt;
  }
</script>
<script>
  const article = document.getElementById('article');
  const html = `<svg width="300" height="560px" xmlns="http://www.w3.org/2000/svg">
  <foreignObject width="100%" height="100%">
    <div xmlns="http://www.w3.org/1999/xhtml">${ html2Text(article) }</div>
  </foreignObject>
</svg>`;
  // nodeName
  const img = new Image();
  const svg = new Blob(html.split(''), {
    type: 'image/svg+xml;charset=utf-8'
  });
  const url = window.URL.createObjectURL(svg);
  function onCanvasAnimationEnd(event){
    this.removeEventListener('animationend', onCanvasAnimationEnd);
    const father = this.parentNode;
    father.removeChild(this);
  }
  function imgLoad(event){
    for(let i = 0; i < 4; i++){
      let canvas = document.getElementById('canvas_' + i);
      let ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0);
      canvas.addEventListener('animationend', onCanvasAnimationEnd, false);
      canvas = ctx = null;
    }
    window.URL.revokeObjectURL(url);
  }
  img.src = url;
  img.addEventListener('load', imgLoad, false);
</script>
</body>
</html>

好吧,SVG版的DEMO也可以哟。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    body { margin: 0; }
    .article { box-sizing: border-box; margin: 0 auto; padding: 10px; width: 300px; height: 560px; border: 1px solid #ddd; border-radius: 5px; background-color: #fff; }
    .article-title { font-size: 16px; }
    .article-secondtitle { font-size: 12px; color: #7e7e7e; }
    .article-title, .article-secondtitle { text-align: center; }
    .article p { font-size: 14px; }
    .svg { position: fixed; top: 0; left: 50%; display: block; width: 300px; height: 560px; margin: 0 0 0 -152px; border: 1px solid #ddd; border-radius: 5px; }

    @keyframes body1{
      0% { transform: rotateZ(0) rotateY(0) scale(1) ; }
      50% { transform: rotateZ(180deg) rotateY(0) scale(.9) ; }
      100% { transform: rotateZ(360deg) rotateY(180deg) scale(0); }
    }
    .animate {
      animation-name: body1;
      animation-timing-function: linear;
      animation-fill-mode: forwards;
    }
    .ani0 { animation-delay: 1s; animation-duration: 2s; z-index: 4; }
    .ani1 { animation-delay: 1.4s; animation-duration: 1.7s; z-index: 3; }
    .ani2 { animation-delay: 1.8s; animation-duration: 1.4s; z-index: 2; }
    .ani3 { animation-delay: 2.2s; animation-duration: 1.1s; z-index: 1; }
  </style>
</head>
<body>
<article class="article" id="article">
  <h1 class="article-title">将进酒·君不见黄河之水天上来</h1>
  <h6 class="article-secondtitle">[唐] 李白</h6>
  <p>君不见黄河之水天上来,奔流到海不复回。</p>
  <p>君不见高堂明镜悲白发,朝如青丝暮成雪。</p>
  <p>人生得意须尽欢,莫使金樽空对月。</p>
  <p>天生我材必有用,千金散尽还复来。</p>
  <p>烹羊宰牛且为乐,会须一饮三百杯。</p>
  <p>岑夫子,丹丘生,将进酒,杯莫停。</p>
  <p>与君歌一曲,请君为我侧耳听。</p>
  <p>钟鼓馔玉不足贵,但愿长醉不复醒。</p>
  <p>古来圣贤皆寂寞,惟有饮者留其名。</p>
  <p>陈王昔时宴平乐,斗酒十千恣欢谑。</p>
  <p>主人何为言少钱,径须沽取对君酌。</p>
  <p>五花马,千金裘,</p>
  <p>呼儿将出换美酒,与尔同销万古愁。</p>
</article>
<!-- 特效代码 -->
<script>

  function style2String(node){
    const css = window.getComputedStyle(node);
    let style = '';
    style += `padding: ${ css.padding }; `;
    style += `width: ${ css.width }; `;
    style += `font-size: ${ css.fontSize }; `;
    style += `font-family: ${ css.fontFamily.replace(/"/g, '') }; `;
    style += `border-radius: ${ css.borderRadius }; `;
    style += `color: ${ css.color }; `;
    style += `text-align: ${ css.textAlign }; `;
    style += `background-color: ${ css.backgroundColor }; `;
    return style;
  }

  function html2Text(node){
    // 节点
    let txt = '';
    if(node.nodeName !== '#text'){
      const nodeName = node.nodeName.toLowerCase();
      const style = style2String(node);
      txt += `<${ nodeName } style="${ style }">`;
      // 子节点
      const childNodes = node.childNodes;
      for(let i = 0, j = childNodes.length; i < j; i++){
        txt += html2Text(childNodes[i]);
      }
      txt += `</${ nodeName }>`;
    }else{
      txt += node.data;
    }
    return txt;
  }
</script>
<script>
  const body = document.body;
  const article = document.getElementById('article');
  const html = `<svg width="300" height="560px" xmlns="http://www.w3.org/2000/svg">
  <foreignObject width="100%" height="100%">
    <div xmlns="http://www.w3.org/1999/xhtml">${ html2Text(article) }</div>
  </foreignObject>
</svg>`;
  function onCanvasAnimationEnd(event){
    this.removeEventListener('animationend', onCanvasAnimationEnd);
    const father = this.parentNode;
    father.removeChild(this);
  }
  for(let i = 0; i < 4; i++){
    let div = document.createElement('div');
    div.innerHTML = html;
    div.className = `svg animate ani${ i }`;
    div.addEventListener('animationend', onCanvasAnimationEnd, true);
    body.appendChild(div);
    div = null;
  }
</script>
</body>
</html>

OVER,觉得很不错的,你可以学习下咯

您的支持是我们创作的动力!
温馨提示:本文作者系 ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://www.jiangweishan.com/article/DOMW123123124124.html

网友评论文明上网理性发言 已有0人参与

发表评论: