3

long story short, I'm making a live line chart and I'm using three.js due to the high number of lines per second that needs to be pushed inside this thing, so, now I'd need to draw the text values for the x and y axis, after a pretty long struggle ( because I'm a total noob @ threejs ) I figured out the wonderful technique of using the canvas as a sprite ( which is darn rad ). This is the code that I use

/// 2D REALM

var canvas = document.createElement('canvas'),
        context = canvas.getContext('2d'),
        metrics = null,
        textHeight = 100,
        textWidth = 0,
        actualFontSize = 2;

        context.fillStyle = '#FF0000';
        var size = 250;
          canvas.width = size;
          canvas.height = size;

function addText(position, text) {
  context.textAlign = 'center';
  context.font = '24px Arial';
  context.fillText("Game Over", size/2, size/2);

  var texture = new THREE.Texture(canvas);
  texture.needsUpdate = true;
  var material = new THREE.SpriteMaterial( { map: texture, color: 0x333333, fog: false } );
  var sprite = new THREE.Sprite( material );
  sprite.position.set(0,100,0);

  return sprite;
}

. . .

 $(document).ready(function() {
   h = $(window).height() - $('.speed-graph').outerHeight() - $('.speed-toolbar').outerHeight() - $('.channel-toolbar').outerHeight() - $('.status_bar').outerHeight() + 1;
      w = $(window).width() - $('.palette').outerWidth();


      camera = new THREE.PerspectiveCamera( 75, parseFloat(w) / parseFloat(h), 0.1, 5000 );


    //renderer.setSize( window.innerWidth, window.innerHeight );
      console.log("w: " + w + " | h: " + h);
      renderer.setSize(w, h);

      $('body').append( renderer.domElement );

      var material = new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 1 });
      var geometry = new THREE.Geometry();

      geometry.vertices.push( new THREE.Vector3(-10 , 0, 0 ) );
      geometry.vertices.push( new THREE.Vector3(8 , 0, 0 ) );

      lines['line'].push(  new THREE.Line( geometry, material ))
      text = addText(new Array(0, 9), "lorem ipsum");
      //lines['label'].push( addText(new Array(0, 9), "0") );
      scene.add( lines['line'][0] );
      scene.add( text );


      camera.position.z = 5;
      render(); 
});

now, the lines get drawn as they should, but I had no luck at all with the text. I can't understand the reason why I can't see the text, because I don't get any compiler error.

holographix
  • 2,497
  • 2
  • 32
  • 46

2 Answers2

7

in the end, I figured it out by myself, problem was that the canvas didn't had a proper size, plus a bunch of other stuff.

for the sake of the solution, and hoping to help others in the future, here's the working code along with a codepen to see it live in action.

/// 2D REALM

//var canvas = document.createElement('canvas'),
var canvas,
  context,
  metrics = null,
  textHeight = 10,
  textWidth = 0,
  actualFontSize = 0.8;

canvas = document.createElement('canvas'),
  context = canvas.getContext('2d');
context.fillStyle = '#FF0000';


function addText(position, text) {
  // 2d duty
  metrics = context.measureText(text);
  var textWidth = metrics.width;

  canvas.width = textWidth;
  canvas.height = textHeight;
  context.font = "normal " + textHeight + "px Arial";
  context.textAlign = "center";
  context.textBaseline = "middle";
  context.fillStyle = "#ff0000";
  context.fillText(text, textWidth / 2, textHeight / 2);

  var texture = new THREE.Texture(canvas);
  texture.needsUpdate = true;
  var material = new THREE.SpriteMaterial({
    map: texture,
    useScreenCoordinates: false
  });
  var sprite = new THREE.Sprite(material);

  var textObject = new THREE.Object3D();
  // var sprite = new THREE.Sprite(texture);
  textObject.textHeight = actualFontSize;
  textObject.textWidth = (textWidth / textHeight) * textObject.textHeight;
  sprite.scale.set(textWidth / textHeight * actualFontSize, actualFontSize, 1);

  //  sprite.position.set(10,10,0);

  textObject.add(sprite);
  return textObject;
}

var scene = new THREE.Scene();
var camera;
var renderer = new THREE.WebGLRenderer({
  alpha: 1,
  antialias: true,
  clearColor: 0xffffff
});


$(document).ready(function() {
  h = $(window).height();
  w = $(window).width();


  camera = new THREE.PerspectiveCamera(75, parseFloat(w) / parseFloat(h), 0.1, 5000);

  // console.log("w: " + w + " | h: " + h);
  renderer.setSize(w, h);

  $('body').append(renderer.domElement);

  text = addText(new Array(0, 9), "it fucking works!!");
  scene.add(text);
  // console.log(text.position);
  //      text.position.x = 3.0;

  camera.position.z = 5;
  render();
});

// render the whole things up
function render() {

  requestAnimationFrame(render);
  renderer.render(scene, camera);

}
body {
  margin: 0;
  padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.122.0/build/three.min.js"></script>
Gangula
  • 5,193
  • 4
  • 30
  • 59
holographix
  • 2,497
  • 2
  • 32
  • 46
  • 2
    Text is hell blurry – a_developer Feb 27 '17 at 22:40
  • Same here, trying many solutions from https://stackoverflow.com/questions/15661339/how-do-i-fix-blurry-text-in-my-html5-canvas but in vain. – Avi Jun 27 '19 at 13:43
  • I think referring to the [three.js editor](https://threejs.org/editor/) code for [ViewHelper](https://github.com/mrdoob/three.js/blob/105b07d3f9f30e6e8a4fe0014137c1a236523d46/editor/js/Viewport.ViewHelper.js#L282) might help. They have a implemented this for the AxesHelper – Gangula Jun 22 '23 at 09:48
0
const o=Object.assign({},defaultFont,conf)
    const canvas = document.createElement('canvas')
    canvasCache.add(canvas)
    canvas.height=o.size!
    canvas.width=text.length*o.size!
    const ctx = canvas.getContext('2d')!
    ctx.font = `Bold ${o.size!}px ${o.face!}`
    const metrics = ctx.measureText(text);
    const width = metrics.width;
    //  ctx.fillStyle = o.bg instanceof THREE.Color ? o.bg.getStyle() : RGBAToCss(o)
    //  canvas.width=width
    //  canvas.height=o.size!
    // ctx.lineWidth = 4
    ctx.textAlign = 'center'
    ctx.textBaseline = "middle"
    ctx.fillStyle =buildColor(o.color!)
    ctx.fillText(text, width/2, o.size!/2)

this same fine to me, I'd know why must set canvas width and height before do any

Zen
  • 1