如何获取 CSS 3D 转换画布的画布相对鼠标位置? [英] How to get a canvas relative mouse position of a CSS 3D transformed canvas?

查看:36
本文介绍了如何获取 CSS 3D 转换画布的画布相对鼠标位置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

只是为了好玩,我试图在 3D 转换的画布上绘画.我写了一些代码,它有点工作

const m4 = twgl.m4;[...document.querySelectorAll('canvas')].forEach((canvas) =​​> {const ctx = canvas.getContext('2d');让计数 = 0;canvas.addEventListener('mousemove', (e) => {const pos = getElementRelativeMousePosition(e, canvas);ctx.fillStyle = hsl((count++ % 10)/10, 1, 0.5);ctx.fillRect(pos.x - 1, pos.y - 1, 3, 3);});});函数 getElementRelativeMousePosition(e, elem) {const pos = convertPointFromPageToNode(elem, e.pageX, e.pageY);返回 {x: pos[0],y:位置[1],};}函数 hsl(h, s, l) {return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;}函数 convertPointFromPageToNode(elem, pageX, pageY) {const mat = m4.inverse(getTransformationMatrix(elem));返回 m4.transformPoint(mat, [pageX, pageY, 0]);};函数 getTransformationMatrix(elem) {让矩阵 = m4.identity();让 currentElem = elem;while (currentElem !== undefined &&currentElem !== currentElem.ownerDocument.documentElement) {const style = window.getComputedStyle(currentElem);const localMatrix = parseMatrix(style.transform);矩阵 = m4.multiply(localMatrix, 矩阵);currentElem = currentElem.parentElement;}const w = elem.offsetWidth;const h = elem.offsetHeight;让我 = 4;让左 = +无穷大;让顶部 = +无穷大;for (让 i = 0; i <4; ++i) {const p = m4.transformPoint(matrix, [w * (i & 1), h * ((i & 2) >> 1), 0]);left = Math.min(p[0], left);顶部 = Math.min(p[1], 顶部);}const rect = elem.getBoundingClientRect()document.querySelector('p').textContent =`${w}x${h}`;矩阵 = m4.multiply(m4.translation([window.pageXOffset + rect.left - 左,window.pageYOffset + rect.top - 顶部,0]), 矩阵);返回矩阵;}函数 parseMatrix(str) {如果(str.startsWith('matrix3d(')){return str.substring(9, str.length - 1).split(',').map(v => parseFloat(v.trim()));} else if (str.startsWith('matrix(')) {const m = str.substring(7, str.length - 1).split(',').map(v => parseFloat(v.trim()));返回 [m[0], m[1], 0, 0,m[2], m[3], 0, 0,0, 0, 1, 0,m[4], m[5], 0, 1,]} else if (str == 'none') {返回 m4.identity();}throw new Error('未知格式');}

canvas {显示:块;背景:黄色;变换:比例(0.75);}#c1 {边距:20px;背景:红色;变换:translateX(-50px);显示:内联块;}#c2 {边距:20px;背景:绿色;变换:旋转(45度);显示:内联块;}#c3 {边距:20px;背景:蓝色;显示:内联块;}#c4 {位置:绝对;顶部:0;背景:青色;变换:translateX(-250px)旋转(55度);显示:内联块;}#c5 {背景:洋红色;变换:翻译(50px);显示:内联块;}#c6 {背景:粉红色;变换:旋转(45度);显示:内联块;}

<p>富</p><div id="c1"><div id="c2"><div id="c3"><canvas></canvas>

<div id="c4"><div id="c5"><div id="c6"><canvas></canvas>

<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

上面的代码有效.将鼠标移到任一黄色画布元素上,您会看到它正确绘制.

但是,一旦我添加了一些 3D 变换,它就会失败.

将#c6"的 CSS 更改为

 #c6 {背景:粉红色;变换:旋转(45度)rotateX(45度);/* 改变了 */显示:内联块;}

现在当我在右边的黄色画布上画画时,一切都结束了.

const m4 = twgl.m4;[...document.querySelectorAll('canvas')].forEach((canvas) =​​> {const ctx = canvas.getContext('2d');让计数 = 0;canvas.addEventListener('mousemove', (e) => {const pos = getElementRelativeMousePosition(e, canvas);ctx.fillStyle = hsl((count++ % 10)/10, 1, 0.5);ctx.fillRect(pos.x - 1, pos.y - 1, 3, 3);});});函数 getElementRelativeMousePosition(e, elem) {const pos = convertPointFromPageToNode(elem, e.pageX, e.pageY);返回 {x: pos[0],y:位置[1],};}函数 hsl(h, s, l) {return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;}函数 convertPointFromPageToNode(elem, pageX, pageY) {const mat = m4.inverse(getTransformationMatrix(elem));返回 m4.transformPoint(mat, [pageX, pageY, 0]);};函数 getTransformationMatrix(elem) {让矩阵 = m4.identity();让 currentElem = elem;while (currentElem !== undefined &&currentElem !== currentElem.ownerDocument.documentElement) {const style = window.getComputedStyle(currentElem);const localMatrix = parseMatrix(style.transform);矩阵 = m4.multiply(localMatrix, 矩阵);currentElem = currentElem.parentElement;}const w = elem.offsetWidth;const h = elem.offsetHeight;让我 = 4;让左 = +无穷大;让顶部 = +无穷大;for (让 i = 0; i <4; ++i) {const p = m4.transformPoint(matrix, [w * (i & 1), h * ((i & 2) >> 1), 0]);left = Math.min(p[0], left);顶部 = Math.min(p[1], 顶部);}const rect = elem.getBoundingClientRect()document.querySelector('p').textContent =`${w}x${h}`;矩阵 = m4.multiply(m4.translation([window.pageXOffset + rect.left - 左,window.pageYOffset + rect.top - 顶部,0]), 矩阵);返回矩阵;}函数 parseMatrix(str) {如果(str.startsWith('matrix3d(')){return str.substring(9, str.length - 1).split(',').map(v => parseFloat(v.trim()));} else if (str.startsWith('matrix(')) {const m = str.substring(7, str.length - 1).split(',').map(v => parseFloat(v.trim()));返回 [m[0], m[1], 0, 0,m[2], m[3], 0, 0,0, 0, 1, 0,m[4], m[5], 0, 1,]} else if (str == 'none') {返回 m4.identity();}throw new Error('未知格式');}

canvas {显示:块;背景:黄色;变换:比例(0.75);}#c1 {边距:20px;背景:红色;变换:translateX(-50px);显示:内联块;}#c2 {边距:20px;背景:绿色;变换:旋转(45度);显示:内联块;}#c3 {边距:20px;背景:蓝色;显示:内联块;}#c4 {位置:绝对;顶部:0;背景:青色;变换:translateX(-250px)旋转(55度);显示:内联块;}#c5 {背景:洋红色;变换:翻译(50px);显示:内联块;}#c6 {背景:粉红色;变换:旋转(45度)rotateX(45度);显示:内联块;}

<p>富</p><div id="c1"><div id="c2"><div id="c3"><canvas></canvas>

<div id="c4"><div id="c5"><div id="c6"><canvas></canvas>

<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

知道我做错了什么吗?

解决方案

注意:这只是 OP 自己已经找到的答案的补充.

您实际上可以通过使用 MouseEvent 来完成这一切构造函数.

您可以在构造函数中传递此事件的 clientXclientY 属性(或 pageX & pageY> 如果您愿意),则将此组合事件分派到您的目标将设置其相对于目标的 offsetXoffsetY 属性.

由于 dispatchEvent 确实同步触发了 Event,我们甚至可以制作一个转换器:

const init_pos = { x: 50, y: 50};const relative_pos = {};const canvas = document.querySelector('canvas');canvas.addEventListener('mousemove', e => {relative_pos.x = e.offsetX;relative_pos.y = e.offsetY;}, {一次:真});canvas.dispatchEvent(new MouseEvent('mousemove', {客户端X:init_pos.x,客户:init_pos.y}));//同步记录console.log(relative_pos);

canvas {显示:块;背景:黄色;变换:比例(0.75);}#c4 {位置:绝对;顶部:0;背景:青色;变换:translateX(-250px)旋转(55度);显示:内联块;}#c5 {背景:洋红色;变换:翻译(50px);显示:内联块;}#c6 {背景:粉红色;变换:旋转(45度);显示:内联块;}

<div id="c5"><div id="c6"><canvas></canvas>

现在,以您自己的答案中的示例为例,您可能希望实际持有一个对象来保持全局事件的位置,并在 requestAnimationFrame循环.
然而,这个设置显然会遍历你的画布,如果你只想要可见的面来处理事件,那么你必须检查哪个与 document.elementFromPoint(x, y) 匹配,它本身需要您的元素对指针事件做出反应.

//将保持我们最后一个事件的位置常量位置 = {x: 0,y:0};const canvases = document.querySelectorAll('canvas');//一个单一的全局真实"MouseEvent 处理程序document.body.onmousemove = (e) =>{pos.x = e.clientX;pos.y = e.clientY;};canvases.forEach(canvas => {const ctx = canvas.getContext('2d');让计数 = 0;canvas.addEventListener('mousemove', draw);函数绘制(e){//不触发真实事件如果(e.cancelable)返回;const x = e.offsetX * canvas.width/canvas.clientWidth;const y = e.offsetY * canvas.height/canvas.clientHeight;if (x < 0 || x > canvas.width || y < 0 || y > canvas.height) {返回;}ctx.fillStyle = hsl((count++ % 10)/10, 1, 0.5);ctx.fillRect(x - 1, y - 1, 3, 3);}});动画();函数动画(){请求动画帧(动画);//如果我们只想在前面的元素上绘画const front_elem = single_face.checked &&document.elementFromPoint(pos.x, pos.y);//在每一帧canvases.forEach(c => {if (!front_elem || c === front_elem) {//强制组合事件(同步,所以我们仍然在 rAF 回调中)c.dispatchEvent(新鼠标事件('鼠标移动',{客户X:pos.x,客户:pos.y}));}});}函数 hsl(h, s, l) {return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;}

.scene {宽度:200px;高度:200px;视角:600px;}.cube {宽度:100%;高度:100%;位置:相对;变换风格:preserve-3d;动画持续时间:16s;动画名称:旋转;动画迭代次数:无限;动画计时功能:线性;指针事件:无;/* 不需要鼠标事件 */}#single_face:checked+.scene .cube {指针事件:全部;/* 除非我们想找出谁是最前面的 */}标签,#single_face {浮动:右}@关键帧旋转{从 {变换:translateZ(-100px)rotateX(0deg)rotateY(0deg);}到 {变换:translateZ(-100px)rotateX(360deg)rotateY(720deg);}}.cube__face {位置:绝对;宽度:200px;高度:200px;显示:块;}.cube__face--前面{背景:rgba(255, 0, 0, 0.2);变换:rotateY(0deg) translateZ(100px);}.cube__face--右{背景:rgba(0, 255, 0, 0.2);变换:rotateY(90deg) translateZ(100px);}.cube__face--back {背景:rgba(0, 0, 255, 0.2);变换:rotateY(180deg) translateZ(100px);}.cube__face--left {背景:rgba(255, 255, 0, 0.2);变换:rotateY(-90deg) translateZ(100px);}.cube__face--top {背景:RGBA(0, 255, 255, 0.2);变换:rotateX(90deg) translateZ(100px);}.cube__face--底部{背景:rgba(255, 0, 255, 0.2);变换:rotateX(-90deg) translateZ(100px);}

<div class="场景"><div class="cube"><canvas class="cube__face cube__face--front"></canvas><canvas class="cube__face cube__face--back"></canvas><canvas class="cube__face cube__face--right"></canvas><canvas class="cube__face cube__face--left"></canvas><canvas class="cube__face cube__face--top"></canvas><canvas class="cube__face cube__face--bottom"></canvas>

<pre id="debug"></pre>

Just for fun I'm trying to draw on 3D transformed canvases. I wrote some code and it kind of works

const m4 = twgl.m4;

[...document.querySelectorAll('canvas')].forEach((canvas) => {
  const ctx = canvas.getContext('2d');
  let count = 0;

  canvas.addEventListener('mousemove', (e) => {
    const pos = getElementRelativeMousePosition(e, canvas);
    ctx.fillStyle = hsl((count++ % 10) / 10, 1, 0.5);
    ctx.fillRect(pos.x - 1, pos.y - 1, 3, 3);
  });
});

function getElementRelativeMousePosition(e, elem) {
  const pos = convertPointFromPageToNode(elem, e.pageX, e.pageY); 
  
  return {
    x: pos[0],
    y: pos[1],
  };
}

function hsl(h, s, l) {
  return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}

function convertPointFromPageToNode(elem, pageX, pageY) {
  const mat = m4.inverse(getTransformationMatrix(elem));
  return m4.transformPoint(mat, [pageX, pageY, 0]);
};

function getTransformationMatrix(elem) {
  let matrix = m4.identity();
  let currentElem = elem;

  while (currentElem !== undefined && 
         currentElem !== currentElem.ownerDocument.documentElement) {
    const style = window.getComputedStyle(currentElem);
    const localMatrix = parseMatrix(style.transform);
    matrix = m4.multiply(localMatrix, matrix);
    currentElem = currentElem.parentElement;
  }

  const w = elem.offsetWidth;
  const h = elem.offsetHeight;
  let i = 4;
  let left = +Infinity;
  let top = +Infinity;
  for (let i = 0; i < 4; ++i) {
    const p = m4.transformPoint(matrix, [w * (i & 1), h * ((i & 2) >> 1), 0]);
    left = Math.min(p[0], left);
    top = Math.min(p[1], top);
  }
  const rect = elem.getBoundingClientRect()
  document.querySelector('p').textContent =
    `${w}x${h}`;
  matrix =  m4.multiply(m4.translation([
     window.pageXOffset + rect.left - left, 
     window.pageYOffset + rect.top - top,
     0]), matrix);
  return matrix;
}


function parseMatrix(str) {
  if (str.startsWith('matrix3d(')) {
    return str.substring(9, str.length - 1).split(',').map(v => parseFloat(v.trim()));
  } else if (str.startsWith('matrix(')) {
    const m = str.substring(7, str.length - 1).split(',').map(v => parseFloat(v.trim()));
    return [
      m[0], m[1], 0, 0,
      m[2], m[3], 0, 0,
      0, 0, 1, 0,
      m[4], m[5], 0, 1,
    ]
  } else if (str == 'none') {
    return m4.identity();
  }
  throw new Error('unknown format');
}

canvas { 
  display: block;
  background: yellow;
  transform: scale(0.75);
}
#c1 {
  margin: 20px;
  background: red;
  transform: translateX(-50px);
  display: inline-block;
}
#c2 {
  margin: 20px;
  background: green;
  transform: rotate(45deg);
  display: inline-block;
}
#c3 {
  margin: 20px;
  background: blue;
  display: inline-block;
}

#c4 {
  position: absolute;
  top: 0;
  background: cyan;
  transform: translateX(-250px) rotate(55deg);
  display: inline-block;
}
#c5 {
  background: magenta;
  transform: translate(50px);
  display: inline-block;
}
#c6 {
  background: pink;
  transform: rotate(45deg);
  display: inline-block;
}

<p>
foo
</p>
<div id="c1">
  <div id="c2">
    <div id="c3">
      <canvas></canvas>
    </div>
  </div>
</div>
<div id="c4">
  <div id="c5">
    <div id="c6">
      <canvas></canvas>
    </div>
  </div>
</div>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

The code above works. Move the mouse over either of the yellow canvas elements and you'll see it draws correctly.

But, as soon as I add some 3D transform it fails.

Change the CSS for '#c6' to

    #c6 {
      background: pink;
      transform: rotate(45deg) rotateX(45deg);  /* changed */
      display: inline-block;
    }

and now when I draw over the right yellow canvas things are off.

const m4 = twgl.m4;

[...document.querySelectorAll('canvas')].forEach((canvas) => {
  const ctx = canvas.getContext('2d');
  let count = 0;

  canvas.addEventListener('mousemove', (e) => {
    const pos = getElementRelativeMousePosition(e, canvas);
    ctx.fillStyle = hsl((count++ % 10) / 10, 1, 0.5);
    ctx.fillRect(pos.x - 1, pos.y - 1, 3, 3);
  });
});

function getElementRelativeMousePosition(e, elem) {
  const pos = convertPointFromPageToNode(elem, e.pageX, e.pageY); 
  
  return {
    x: pos[0],
    y: pos[1],
  };
}

function hsl(h, s, l) {
  return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}

function convertPointFromPageToNode(elem, pageX, pageY) {
  const mat = m4.inverse(getTransformationMatrix(elem));
  return m4.transformPoint(mat, [pageX, pageY, 0]);
};

function getTransformationMatrix(elem) {
  let matrix = m4.identity();
  let currentElem = elem;

  while (currentElem !== undefined && 
         currentElem !== currentElem.ownerDocument.documentElement) {
    const style = window.getComputedStyle(currentElem);
    const localMatrix = parseMatrix(style.transform);
    matrix = m4.multiply(localMatrix, matrix);
    currentElem = currentElem.parentElement;
  }

  const w = elem.offsetWidth;
  const h = elem.offsetHeight;
  let i = 4;
  let left = +Infinity;
  let top = +Infinity;
  for (let i = 0; i < 4; ++i) {
    const p = m4.transformPoint(matrix, [w * (i & 1), h * ((i & 2) >> 1), 0]);
    left = Math.min(p[0], left);
    top = Math.min(p[1], top);
  }
  const rect = elem.getBoundingClientRect()
  document.querySelector('p').textContent =
    `${w}x${h}`;
  matrix =  m4.multiply(m4.translation([
     window.pageXOffset + rect.left - left, 
     window.pageYOffset + rect.top - top,
     0]), matrix);
  return matrix;
}


function parseMatrix(str) {
  if (str.startsWith('matrix3d(')) {
    return str.substring(9, str.length - 1).split(',').map(v => parseFloat(v.trim()));
  } else if (str.startsWith('matrix(')) {
    const m = str.substring(7, str.length - 1).split(',').map(v => parseFloat(v.trim()));
    return [
      m[0], m[1], 0, 0,
      m[2], m[3], 0, 0,
      0, 0, 1, 0,
      m[4], m[5], 0, 1,
    ]
  } else if (str == 'none') {
    return m4.identity();
  }
  throw new Error('unknown format');
}

canvas { 
  display: block;
  background: yellow;
  transform: scale(0.75);
}
#c1 {
  margin: 20px;
  background: red;
  transform: translateX(-50px);
  display: inline-block;
}
#c2 {
  margin: 20px;
  background: green;
  transform: rotate(45deg);
  display: inline-block;
}
#c3 {
  margin: 20px;
  background: blue;
  display: inline-block;
}

#c4 {
  position: absolute;
  top: 0;
  background: cyan;
  transform: translateX(-250px) rotate(55deg);
  display: inline-block;
}
#c5 {
  background: magenta;
  transform: translate(50px);
  display: inline-block;
}
#c6 {
  background: pink;
  transform: rotate(45deg) rotateX(45deg);
  display: inline-block;
}

<p>
foo
</p>
<div id="c1">
  <div id="c2">
    <div id="c3">
      <canvas></canvas>
    </div>
  </div>
</div>
<div id="c4">
  <div id="c5">
    <div id="c6">
      <canvas></canvas>
    </div>
  </div>
</div>
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>

Any ideas what I'm doing wrong?

解决方案

Note: That's just a complementary answer on what OP already did find by themselves.

You can actually make this all work by using the MouseEvent constructor.

You can pass the clientX and clientY properties of this Event inside the constructor (or pageX & pageY if you prefer), then dispatching this composed event to your target will set its offsetX and offsetY properties relative to the target.

Since dispatchEvent does fire the Event synchronously, we can even make a converter:

const init_pos = { x: 50, y: 50};
const relative_pos = {};
const canvas = document.querySelector('canvas');

canvas.addEventListener('mousemove', e => {
  relative_pos.x = e.offsetX;
  relative_pos.y = e.offsetY;
}, {once: true});

canvas.dispatchEvent(new MouseEvent('mousemove', {
  clientX: init_pos.x,
  clientY: init_pos.y
}));
// synchronously log
console.log(relative_pos);

canvas { 
  display: block;
  background: yellow;
  transform: scale(0.75);
}
#c4 {
  position: absolute;
  top: 0;
  background: cyan;
  transform: translateX(-250px) rotate(55deg);
  display: inline-block;
}
#c5 {
  background: magenta;
  transform: translate(50px);
  display: inline-block;
}
#c6 {
  background: pink;
  transform: rotate(45deg);
  display: inline-block;
}

<div id="c4">
  <div id="c5">
    <div id="c6">
      <canvas></canvas>
    </div>
  </div>
</div>

Now, given the example in your own answer, you may want to actually hold a single object that will keep the global Event's position, and to get the relative positions of your canvas at every frame in a requestAnimationFrame loop.
However, this setup will obviously traverse your canvases, if you want only the visible face to handle the events, then you'd have to check which one matches document.elementFromPoint(x, y), which itself needs your elements to react to pointer-events.

// will hold our last event's position
const pos = {
  x: 0,
  y: 0
};
const canvases = document.querySelectorAll('canvas');
// A single global "real" MouseEvent handler
document.body.onmousemove = (e) => {
  pos.x = e.clientX;
  pos.y = e.clientY;
};

canvases.forEach(canvas => {
  const ctx = canvas.getContext('2d');
  let count = 0;
  canvas.addEventListener('mousemove', draw);
  function draw(e) {
    // do not fire on real Events
    if (e.cancelable) return;
    
    const x = e.offsetX * canvas.width / canvas.clientWidth;
    const y = e.offsetY * canvas.height / canvas.clientHeight;
    
    if (x < 0 || x > canvas.width || y < 0 || y > canvas.height) {
      return;
    }
    
    ctx.fillStyle = hsl((count++ % 10) / 10, 1, 0.5);
    ctx.fillRect(x - 1, y - 1, 3, 3);
  }
});

anim();

function anim() {
  requestAnimationFrame(anim);

  // in case we want to paint only on the front element
  const front_elem = single_face.checked && document.elementFromPoint(pos.x, pos.y);

  // at every frame
  canvases.forEach(c => {
    if (!front_elem || c === front_elem) {
      // force a composed event (synchronously, so we are still in rAF callback)
      c.dispatchEvent(
        new MouseEvent('mousemove', {
          clientX: pos.x,
          clientY: pos.y
        })
      );
    }
  });
}

function hsl(h, s, l) {
  return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}

.scene {
  width: 200px;
  height: 200px;
  perspective: 600px;
}

.cube {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  animation-duration: 16s;
  animation-name: rotate;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
  pointer-events: none; /* no need for mouse events */
}

#single_face:checked+.scene .cube {
  pointer-events: all; /* except if we want to find out who is the front one */
}
label,#single_face {float: right}
@keyframes rotate {
  from {
    transform: translateZ(-100px) rotateX( 0deg) rotateY( 0deg);
  }
  to {
    transform: translateZ(-100px) rotateX(360deg) rotateY(720deg);
  }
}

.cube__face {
  position: absolute;
  width: 200px;
  height: 200px;
  display: block;
}

.cube__face--front {
  background: rgba(255, 0, 0, 0.2);
  transform: rotateY( 0deg) translateZ(100px);
}

.cube__face--right {
  background: rgba(0, 255, 0, 0.2);
  transform: rotateY( 90deg) translateZ(100px);
}

.cube__face--back {
  background: rgba(0, 0, 255, 0.2);
  transform: rotateY(180deg) translateZ(100px);
}

.cube__face--left {
  background: rgba(255, 255, 0, 0.2);
  transform: rotateY(-90deg) translateZ(100px);
}

.cube__face--top {
  background: rgba(0, 255, 255, 0.2);
  transform: rotateX( 90deg) translateZ(100px);
}

.cube__face--bottom {
  background: rgba(255, 0, 255, 0.2);
  transform: rotateX(-90deg) translateZ(100px);
}

<label>Draw on a single face</label><input type="checkbox" id="single_face">
<div class="scene">
  <div class="cube">
    <canvas class="cube__face cube__face--front"></canvas>
    <canvas class="cube__face cube__face--back"></canvas>
    <canvas class="cube__face cube__face--right"></canvas>
    <canvas class="cube__face cube__face--left"></canvas>
    <canvas class="cube__face cube__face--top"></canvas>
    <canvas class="cube__face cube__face--bottom"></canvas>
  </div>
</div>
<pre id="debug"></pre>

这篇关于如何获取 CSS 3D 转换画布的画布相对鼠标位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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