在控制台中的位置获取画布中的像素颜色

时间:2017-05-18 18:33:37

标签: javascript html5 debugging canvas

我想在Chrome控制台中调试我的html5画布。我想在位置(445,650)获得像素颜色。

我尝试使用此代码:

var example = document.getElementById('glcanvas');
var context = example.getContext('2d');
var data = context.getImageData(x, y, 1, 1).data;

当我一个接一个地运行这些行时,我得到:

example
<canvas class="topleft" id="glcanvas" width="479" height="616" tabindex="1" contenteditable="true" style="cursor: default; width: 479px; height: 616px;"></canvas>

context
null

如何获得非null 上下文?

2 个答案:

答案 0 :(得分:1)

Canvas元素可以附加仅一个渲染上下文。每次在第一次初始化后调用getContext(type)时,如果您使用相同的type参数,它将返回相同的上下文对象,如果您使用了其他上下文,则返回null type

从您的标记中可以看出,您的画布上附有了webgl上下文 因此,当您致电getContext('2d')时,它会返回null

以下是一个示例,说明如何在未直接初始化的上下文中使用它。 webgl的getImageData 等效方法readPixels()

// we have access to the DOM element
var canvas = document.querySelector('canvas');
// we need to get the correct context type, or it will return null
var gl = canvas.getContext('webgl') || canvas.getContext('webgl2');
// where we'll store our pixels info
var pixels = new Uint8Array(4);

canvas.addEventListener('click', function(e) {
  var x = e.clientX - canvas.offsetLeft;
  var y = e.clientY - canvas.offsetTop;
  // we need to call it in the same execution flow as 'render' because webgl erase the drawing buffer by default
  // this can be done by stacking our code in the next frame.
  requestAnimationFrame(function() {
    gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    console.log(pixels);
  });
});

&#13;
&#13;
// we have access to the DOM element
var canvas = document.querySelector('canvas');
// we need to get the correct context type, or it will return null
var gl = canvas.getContext('webgl') || canvas.getContext('webgl2');
// where we'll store our pixels info
var pixels = new Uint8Array(4);

canvas.addEventListener('click', function(e) {
  var x = e.clientX - canvas.offsetLeft;
  var y = e.clientY - canvas.offsetTop;
  // we need to call it in the same execution flow as 'render' because webgl erase the drawing buffer by default
  // this can be done by stacking our code in the next frame.
  requestAnimationFrame(function() {
    gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    console.log(pixels);
  });
});
&#13;
<!-- 
Example of external code, on which we don't have direct access.
Taken from https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_cube.html
-->

<base href="https://threejs.org/examples/">
<script src="../build/three.js"></script>
<script>
(function(){
  var camera, scene, renderer;
  var mesh;
  init();
  animate();
  console.clear();

  function init() {
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.z = 400;
    scene = new THREE.Scene();
    var geometry = new THREE.BoxBufferGeometry(200, 200, 200);
    var material = new THREE.MeshBasicMaterial();
    mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);
    renderer = new THREE.WebGLRenderer();
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    //
    window.addEventListener('resize', onWindowResize, false);
  }

  function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  }

  function animate() {
    requestAnimationFrame(animate);
    mesh.rotation.x += 0.005;
    mesh.rotation.y += 0.01;
    renderer.render(scene, camera);
  }
})();
</script>
&#13;
&#13;
&#13;

请注意,像素读取操作变为异步,并且在此实现中将始终为一帧,因为webgl上下文未使用preserveDrawingBuffer选项进行初始化。如果是,你可以制作同步方法。

还有一种类型不可知的方法:使用屏幕外2d上下文并直接在这个2d上下文中绘制画布。

// the canvas we want to read
var target = document.querySelector('canvas');
// the canvas we'll use to read the target on
var reader = document.createElement('canvas');
var ctx = reader.getContext('2d');

target.addEventListener('click', function(e) {
  var x = e.clientX - target.offsetLeft;
  var y = e.clientY - target.offsetTop;
  // same preserveDrawingBuffer workaround
  requestAnimationFrame(function() {
    // move the target image in the top left corner of our reader,
    //  because we want only a single pixel
    ctx.drawImage(target, -x, -y); 
    var pixels = ctx.getImageData(0, 0, 1, 1);
    console.log(pixels);
  });
});

&#13;
&#13;
// the canvas we want to read
var target = document.querySelector('canvas');
// the canvas we'll use to read the target on
var reader = document.createElement('canvas');
var ctx = reader.getContext('2d');

target.addEventListener('click', function(e) {
  var x = e.clientX - target.offsetLeft;
  var y = e.clientY - target.offsetTop;
  // same preserveDrawingBuffer workaround
  requestAnimationFrame(function() {
    // move the target image in the top left corner of our reader,
    //  because we want only a single pixel
    ctx.drawImage(target, -x, -y); 
    var pixels = ctx.getImageData(0, 0, 1, 1);
    console.log(pixels);
  });
});
&#13;
<!-- 
Example of external code, on which we don't have direct access.
Taken from https://github.com/mrdoob/three.js/blob/master/examples/webgl_geometry_cube.html
-->

<base href="https://threejs.org/examples/">
<script src="../build/three.js"></script>
<script>
  (function() {
    var camera, scene, renderer;
    var mesh;
    init();
    animate();
    console.clear();

    function init() {
      camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
      camera.position.z = 400;
      scene = new THREE.Scene();
      var geometry = new THREE.BoxBufferGeometry(200, 200, 200);
      var material = new THREE.MeshBasicMaterial();
      mesh = new THREE.Mesh(geometry, material);
      scene.add(mesh);
      renderer = new THREE.WebGLRenderer();
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);
      //
      window.addEventListener('resize', onWindowResize, false);
    }

    function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {
      requestAnimationFrame(animate);
      mesh.rotation.x += 0.005;
      mesh.rotation.y += 0.01;
      renderer.render(scene, camera);
    }
  })();
</script>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

实际上您的代码工作正常。

这是一个HTML /脚本代码,其中包含您问题的给定信息。

<html>
<canvas class="topleft" id="glcanvas" width="479" height="616" tabindex="1" contenteditable="true" style="cursor: default; width: 479px; height: 616px;"></canvas>
<script>
var example = document.getElementById('glcanvas');
var context = example.getContext('2d');
var x=445;
var y=650;
var data = context.getImageData(x, y, 1, 1).data;
alert('R:' + data[0] + ' G:' + data[1] + ' B:' + data[2]);
</script>
</html>

可能是在glcanvas-Object初始化之前运行脚本。