将CSS3 matrix3D绘制到画布2D元素

时间:2017-11-07 09:19:44

标签: javascript css css3 canvas transform

我想知道是否有办法使用CSS3 Matrix3D转换将图像绘制到画布中。使用的上下文是2D一个用于渲染堆叠图层的图像图层和一个用matrix3D转换的图像图层(因为我没有设法在画布上绘制它)。

基本上我想要实现的是将transform: matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1)转换为2D上下文中的绘图画布方法。

有可能吗?现在,我对画布上方的CSS3层非常好,但我正在开发的应用程序必须将画布导出到实际的图像文件(意味着发送给用户)。

这是一个片段,说明了我目前显示转换图层的方式。所以这里的目标是实际将“占位符”转换后的图像渲染到画布中

#canvas {
  background: tomato;
  height: 100vh;
  width: 100vw;
  position: relative;
}

.viewport .transformed-layer {
    height: 72%;
    position: absolute;
    left: 35%;
    top: calc(21% - 550px);
    -webkit-transform: rotate(-1.5deg) matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1);
    transform: rotate(-1.5deg) matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1);
    opacity: .9;
}
<div class='viewport'>
  <div id='canvas'>This is a div simulating the canvas element with some drawed image</div>
  <img class='transformed-layer' src='http://via.placeholder.com/300x300' />
</div>

1 个答案:

答案 0 :(得分:2)

有一种黑客攻击可能不符合未来读者的要求,但可能适合你:

画布可以绘制SVG图像,SVG图像可以通过CSS转换。 因此,您可以将当前画布转换为dataURL,将此dataURL设置为SVGImage元素的href,然后将其应用于CSSTransform,然后将所有这些作为svg图像导出,并将其绘制到画布上。

以下是概念的粗略证明:

&#13;
&#13;
function getTransformedCanvas(canvas, CSSTransform){
  return new Promise(function(res, rej){
    var dim = getTransformedDimensions(canvas, CSSTransform);
    var xlinkNS = "http://www.w3.org/1999/xlink",
        svgNS = 'http://www.w3.org/2000/svg';
    var svg = document.createElementNS(svgNS, 'svg'),
      defs = document.createElementNS(svgNS, 'defs'),
      style = document.createElementNS(svgNS, 'style'),
    image = document.createElementNS(svgNS, 'image');
    image.setAttributeNS(xlinkNS, 'href', canvas.toDataURL());
    image.setAttribute('width', canvas.width);
    image.setAttribute('height', canvas.height);
    style.innerHTML = 'image{transform:'+CSSTransform+';}';
    svg.appendChild(defs);
    defs.appendChild(style);
    var rect = document.createElement('rect');

    svg.appendChild(image);
    svg.setAttribute('width', dim.width);
    svg.setAttribute('height', dim.height);
    var svgStr = new XMLSerializer().serializeToString(svg);
    var img = new Image();
    img.onload = function(){res(img)};
    img.onerror = rej;
    img.src = URL.createObjectURL(new Blob([svgStr], {type:'image/svg+xml'}));
  });
}

function getTransformedDimensions(canvas, CSSTransform){
  var orphan = !canvas.parentNode;
  if(orphan) document.body.appendChild(canvas);
  var oldTrans = getComputedStyle(canvas).transform;
  canvas.style.transform = CSSTransform;
  var rect = canvas.getBoundingClientRect();
  canvas.style.transform = oldTrans;
  if(orphan) document.body.removeChild(canvas);
  return rect;
 }

// create a simple checkerboard
var canvas = document.createElement('canvas');
canvas.width = canvas.height = 30;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'orange';
ctx.fillRect(0,0,15, 15);
ctx.fillRect(15,15,15, 15);
var pattern = ctx.createPattern(canvas, 'repeat');
canvas.width = canvas.height = 300;
ctx.fillStyle = pattern;
ctx.fillRect(0,0,300,300);
getTransformedCanvas(canvas, 
 'translateY(-540px) rotate(-1.5deg) matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1)'
 )
 .then(function(img){
  inScreen.width = img.width;
  inScreen.height = img.height;
  inScreen.getContext('2d').drawImage(img, 0,0);
  })
.catch(console.error);
&#13;
canvas {
  border:1px solid;
}
&#13;
<canvas id="inScreen"></canvas>
&#13;
&#13;
&#13;

但是请注意,只要在它上面绘制svg iamge,旧版本的IE确实会污染画布......