如何在 Fabricjs 中鼠标悬停对象时显示对象边界框?

How to show object bounding box when mouse hover objects in Fabricjs?


当鼠标悬停在像这个视频这样的对象上时,我想显示对象边界框,该怎么做?

我正在使用 canvas.on('mouse:over')selectedObj.drawBorders 函数。但是,轮廓框绘制在不正确的位置。而且我不知道如何在鼠标移出对象时清除该轮廓框。

这是我的代码:

$(function() {
  
  var canvasObject = document.getElementById("editorCanvas");

  // set canvas equal size with div
  $(canvasObject).width($("#canvasContainer").width());
  $(canvasObject).height($("#canvasContainer").height());

  var canvas = new fabric.Canvas('editorCanvas', {
   backgroundColor: 'white',
   selectionLineWidth: 2,
   width: $("#canvasContainer").width(),
   height: $("#canvasContainer").height()
  });
  
  canvas.viewportTransform[4] = 20;
     canvas.viewportTransform[5] = 40;
  
  canvas.on('mouse:over', function(opts) {
   var selectedObj = opts.target;
   if (selectedObj != null) {
    selectedObj.drawBorders(canvas.getContext())
   }
  });
  
  var text = new fabric.Text('hello world', { left: 50, top: 50 });
  canvas.add(text);
  
  setObjectCoords();
  
  function setObjectCoords() {
    canvas.forEachObject(function(object) {
   object.setCoords();
    });
  }
  
 });
<style>
  #canvasContainer {
    width: 100%;
    height: 100vh;
    background-color: gray;
  }
</style>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
  
<div id="canvasContainer">
  <canvas id="editorCanvas"></canvas>
</div>

请帮我解决这个问题!
谢谢!

这就是我使用普通 Javascript 的方式: 我使用 ctx.measureText() 方法测量文本。 函数 drawBBox() 正在绘制没有描边的边界框 在 canvas 上移动鼠标时,我检测到鼠标的位置,如果鼠标在框内,我调用 ctx.stroke()。

请阅读我代码中的注释。

虽然我没有使用 fabricjs,但我希望你会发现它有用

let ctx = editorCanvas.getContext("2d");
let cw = editorCanvas.width = canvasContainer.clientWidth,cx = cw/2;
let ch = editorCanvas.height = canvasContainer.clientHeight,cy = ch/2;
let start = {x:50,y:50}// where the text begin


let text = "hello world"; 
//set some properties of the text
ctx.fillStyle = "blue";
ctx.font="2em Verdana";
ctx.textBaseline="hanging";
//draw the text
ctx.fillText(text,start.x,start.y);

let measure = ctx.measureText(text);

function drawBBox(measure){
// a function to draw the bounding box
// the box has no stroke yet
  ctx.beginPath();
  ctx.moveTo(start.x,start.y)
  ctx.lineTo(start.x+measure.width,start.y);
  ctx.lineTo(start.x+measure.width,start.y+36);//36 = 2em: the height of the text
  ctx.lineTo(start.x,start.y+36);
  ctx.closePath();
}



editorCanvas.addEventListener("mousemove",(evt)=>{
  //clear the canvas
  ctx.clearRect(0,0,cw,ch);
  //get the position of the mouse
  let m = oMousePos(editorCanvas, evt);
  //draw the text
  ctx.fillText(text,start.x,start.y);
  // draw the bounding box with no stroke
  drawBBox(measure);
  
  // if the mouse is inside the bounding box apply the stroke
  if(ctx.isPointInPath(m.x, m.y)){
    ctx.stroke()
  }
})


// a function to detect the mouse position
 function oMousePos(canvas, evt) {
  var ClientRect = canvas.getBoundingClientRect();
 return {
 x: Math.round(evt.clientX - ClientRect.left),
 y: Math.round(evt.clientY - ClientRect.top)
  }
 }
#canvasContainer {
    width: 100%;
    height: 100vh;
    background-color: gray;
  }
<div id="canvasContainer">
  <canvas id="editorCanvas"></canvas>
</div>

使用方法 _renderControls 并在 styleOverride 中设置 hasControls : false 仅绘制边框。

演示版

$(function() {
  var canvas = new fabric.Canvas('editorCanvas', {
    backgroundColor: 'white',
    selectionLineWidth: 2,
    width: $("#canvasContainer").width(),
    height: $("#canvasContainer").height()
  });

  var text = new fabric.IText('hello world', {
    left: 50,
    top: 50
  });
  canvas.add(text);
  canvas
  text.on('mouseover', function() {
    this._renderControls(this.canvas.contextTop, {
      hasControls: false
    })
  })
  text.on('mousedown', function() {
    this.canvas.clearContext(this.canvas.contextTop);
  })
  text.on('mouseout', function() {
    this.canvas.clearContext(this.canvas.contextTop);
  })
});
<style>
  #canvasContainer {
    width: 100%;
    height: 100vh;
    background-color: gray;
  }
</style>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
  
<div id="canvasContainer">
  <canvas id="editorCanvas"></canvas>
</div>

fabricjs@4.5.1

它对我有用,像这样:

// mouse:over draw bound box
this._canvas.on('mouse:over', (evet) => {
  const { target } = evet;
  if (this._canvas.getActiveObjects().length) {
    // skip group hover
    return;
  }

  // skip group hover
  if (target instanceof fabric.Object && !(target instanceof Array)) {
    const bound = target.getBoundingRect();
    const ctx = this._canvas.getContext();
    ctx.strokeStyle = 'red';
    ctx.strokeRect(
      bound.left,
      bound.top,
      bound.width,
      bound.height
    );
  }
});
// mouse:out remove bound box
this._canvas.on('mouse:out', (evet) => {
  const { target } = evet;
  if (this._canvas.getActiveObjects().length) {
    return;
  }

  // skipp group hover
  if (target instanceof fabric.Object && !(target instanceof Array)) {
     this._canvas.renderAll(); // render all, will clear bounds box drawed by mouse:over
  }
});