将CSS3 matrix3D绘制到canvas 2D元素 [英] Draw CSS3 matrix3D to a canvas 2D element

查看:99
本文介绍了将CSS3 matrix3D绘制到canvas 2D元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

有可能吗?就目前而言,我对画布上方的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> 

解决方案

有一些骇客可能无法满足任何未来读者的要求,但可能对您有用:

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

以下是概念的粗略证明:

 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); 

 canvas {
  border:1px solid;
} 

 <canvas id="inScreen"></canvas> 

但是请注意,每当在其上绘制svg iamge时,旧版本的IE都会污染画布...

I would like to know if there's a way to draw an image into a canvas using a CSS3 Matrix3D transformation. The used context is a 2D one used to render stacked layers and an image layer transformed with a matrix3D above it (because I didn't manage to have it drawn in the canvas).

So basically what I want to achieve is to convert transform: matrix3d(0.87, 0, 0.5, -0.00025, 0, 1, 0, 0, -0.5, 0, 0.87, 0, 0, 550, 0, 1) into a drawing canvas method in a 2D context.

Is it possible ? For now, I'm quite fine with the CSS3 layer above the canvas but the application I'm developing will have to export the canvas to an actual image file (meant to be sent to the user).

Here's a snippet illustrating my current way of displaying the transformed layer. So the goal here is to actually render the "placeholder" transformed image into the canvas

#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>

解决方案

There is one heck of hack that may not fit any future-readers requirements, but which may do for you:

The canvas can draw SVG images, and SVG images can be transformed via CSS. So you could convert your current canvas to a dataURL, set this dataURL as the href of an SVGImage element, on which you would apply the CSSTransform, before exporting all this as an svg image that you'll draw back on a canvas.

Here is a rough proof of concept:

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);

canvas {
  border:1px solid;
}

<canvas id="inScreen"></canvas>

But note that old versions of IE did taint the canvas whenever an svg iamge was drawn on it...

这篇关于将CSS3 matrix3D绘制到canvas 2D元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆