Что именно я хочу достичь

  1. рисовать объекты на холсте и
  2. при наведении указателя мыши отображать соответствующие данные во всплывающей подсказке.

here вы можете просмотреть код.

var canvasBack;
var canvasLabel;
var canvasDraw;
var ctxBack;
var ctxLabel;
var ctxDraw;
var last_mousex = 0;
var last_mousey = 0;
var mousex = 0;
var mousey = 0;
var canWidth;
var canHeight;
var scaleParameter;
var radius;
var xVertex;
var yVertex;
var hotspots = [];

// initialization on loading of canvas
$('canvas').ready(function() {
  init();
});

// initialization function used for binding events, and inital logic implemented.
function init() {
  scaleParameter = 1;
  canvasBack = document.getElementById('backSpace');
  canvasLabel = document.getElementById('layerCanvas');
  canvasDraw = document.getElementById('drawSpace');
  ctxBack = canvasBack.getContext('2d');
  ctxLabel = canvasLabel.getContext('2d');
  ctxDraw = canvasDraw.getContext('2d');

  canWidth = parseInt($(canvasBack).attr('width'));
  canHeight = parseInt($(canvasBack).attr('height'));

  var canvasx = $(canvasBack).offset().left;
  var canvasy = $(canvasBack).offset().top
  var mousedown = false;

  //Mousedown
  $('canvas').on('mousedown', function(e) {
    $('#drawSpace').css('display', 'block');
    last_mousex = mousex = parseInt(e.clientX - canvasx);
    last_mousey = mousey = parseInt(e.clientY - canvasy);
    mousedown = true;
  });

  //Mouseup
  $('canvas').on('mouseup', function(e) {
    hotspots.push({
      x: xVertex,
      y: yVertex,
      radius: radius,
      tip: 'You are over ' + mousex + ',' + mousey
    });
    let cw = canvasBack.width;
    let ch = canvasBack.height;
    ctxBack.drawImage(canvasDraw, 0, 0, cw, ch);
    $('#drawSpace').css('display', 'none');
    mousedown = false;
  });

  //Mousemove
  $('canvas').on('mousemove', function(e) {
    mousex = parseInt(e.clientX - canvasx);
    mousey = parseInt(e.clientY - canvasy);
    if (mousedown) {
      // draw(mousedown);
      drawEllipse(last_mousex, last_mousey, mousex, mousey);
    } else {
      hoverTooltip();
    }
  });
}


function drawEllipse(x1, y1, x2, y2) {
  var leftScroll = $("#scrollParent").scrollLeft();
  var topScroll = $("#scrollParent").scrollTop();
  let cw = canvasBack.width;
  let ch = canvasBack.height;
  ctxDraw.clearRect(0, 0, cw, ch);
  var radiusX = x2 - x1,
    radiusY = y2 - y1,
    centerX = x1 + radiusX,
    centerY = y1 + radiusY,
    step = 0.01,
    a = step,
    pi2 = Math.PI * 2 - step;

  radius = Math.sqrt(radiusX * radiusX + radiusY * radiusY) / 2;

  ctxDraw.beginPath();
  ctxDraw.arc(centerX, centerY, radius, 0, 2 * Math.PI, true);
  ctxDraw.closePath();
  ctxDraw.fillStyle = 'green';
  ctxDraw.fill();
  ctxDraw.strokeStyle = '#000';
  ctxDraw.stroke();

  xVertex = centerX;
  yVertex = centerY;
}

// tooltip show on hover over objects
function hoverTooltip() {
  var leftScroll = $("#scrollParent").scrollLeft();
  var topScroll = $("#scrollParent").scrollTop();
  let cw = canvasBack.width;
  let ch = canvasBack.height;

  for (var i = 0; i < hotspots.length; i++) {
    var h = hotspots[i];
    var dx = mousex - h.x;
    var dy = mousey - h.y;
    if (dx * dx + dy * dy < h.radius * h.radius) {
      $('#console').text(h.tip);
      ctxLabel.clearRect(0, 0, cw, ch);
      ctxLabel.fillText(h.tip, mousex + leftScroll, mousey + topScroll);
    } else {
      ctxLabel.clearRect(0, 0, cw, ch);
    }
  }
}
#scrollParent {
  width: 644px;
  height: 364px;
  overflow: auto;
  position: relative;
}

#scrollParent>canvas {
  position: absolute;
  left: 0;
  top: 0;
  border: 1px solid #ababab;
}

#backSpace {
  z-index: 0;
}

#drawSpace {
  display: none;
  z-index: 1;
}

#layerCanvas {
  z-index: 2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="scrollParent">
  <!-- actual canvas that is visible -->
  <canvas width="640" height="360" id="backSpace"></canvas>
  <!-- canvas used for drawing new objects -->
  <canvas width="640" height="360" id="drawSpace"></canvas>
  <!-- canvas used to display tooltip -->
  <canvas width="640" height="360" id="layerCanvas"></canvas>
</div>
<div id="console"></div>

</div>

Фактическая проблема заключается в изображении ниже, всплывающая подсказка работала нормально, когда был нарисован 1-й объект, но как только второй объект был нарисован, всплывающая подсказка работала только для второго, а не для ранее нарисованных объектов.

Что вызывает эту проблему и как ее исправить? введите описание изображения здесь

1
Nikhil Kinkar 19 Сен 2018 в 15:11

2 ответа

Лучший ответ

Удаление else не приведет к удалению метки при выходе из эллипса.

Вам нужно выйти из цикла, как только вы найдете правильный эллипс из массива, используя break.

function hoverTooltip() {
  var leftScroll = $("#scrollParent").scrollLeft();
  var topScroll = $("#scrollParent").scrollTop();
  let cw = canvasBack.width;
  let ch = canvasBack.height;

  for (var i = 0; i < hotspots.length; i++) {
    var h = hotspots[i];
    var dx = mousex - h.x;
    var dy = mousey - h.y;
    if (dx * dx + dy * dy < h.radius * h.radius) {
      $('#console').text(h.tip);
      ctxLabel.clearRect(0, 0, cw, ch);
      ctxLabel.fillText(h.tip, mousex + leftScroll, mousey + topScroll);
      break; // exit the loop
    } else {
       ctxLabel.clearRect(0, 0, cw, ch);
    }
  }
}

< Сильный > UPDATE

Я подумал, что если вы нарисуете два объекта друг над другом, это будет плохо себя вести. Попробуйте вместо этого. Он будет отображать информацию о последней нарисованной точке.

function hoverTooltip() {
  var leftScroll = $("#scrollParent").scrollLeft();
  var topScroll = $("#scrollParent").scrollTop();
  let cw = canvasBack.width;
  let ch = canvasBack.height;

  var spots = hotspots.filter((h) => {
    var dx = mousex - h.x;
    var dy = mousey - h.y; 
    return (dx * dx + dy * dy < h.radius * h.radius);
  })

  if (spots.length > 0) {
    var h = spots[spots.length - 1]; // latest drawn spot
    $('#console').text(h.tip);
    ctxLabel.clearRect(0, 0, cw, ch);
    ctxLabel.fillText(h.tip, mousex + leftScroll, mousey + topScroll);
  } 
  else
  {
    ctxLabel.clearRect(0, 0, cw, ch);
  }
}
2
chintuyadavsara 19 Сен 2018 в 13:48

Я вижу, есть уже несколько ответов. Это мое: Чтобы иметь возможность отображать метку для каждого круга при наведении курсора, вам необходимо сохранить все свои круги в массиве am: массив circles. Я использую метод ctx.isPointInPath(), чтобы узнать, находится ли указатель мыши над кругом, и если это так, я раскрашиваю этикетку.

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
let cw = canvas.width = 640;
let ch = canvas.height = 360;

let found = false;//is a circle found?

const cText = document.querySelector("#text");
const ctxText = cText.getContext("2d");
cText.width = 640;
cText.height = 360;
ctxText.font="1em Verdana";


let drawing = false;

let circles = []


class Circle{
  constructor(x,y){
    this.x = x; 
    this.y = y;
    this.r = 0;
  }
  
  updateR(m) {
    this.r = dist(this,m);
  }
  draw(){ 
     ctx.beginPath();
     ctx.arc(this.x,this.y,this.r,0,2*Math.PI);
   }
  paint(){
    ctx.fillStyle = "green";
    ctx.strokeStyle = "black";
    this.draw();
    ctx.stroke();
    ctx.fill();
  }
  
  label(m){
    this.draw();
    if (ctx.isPointInPath(m.x, m.y)) {
    ctx.beginPath();
    ctx.arc(this.x, this.y, 4, 0, 2 * Math.PI);
     
    ctxText.fillStyle = "black";
    ctxText.fillText(`you are over ${this.x},${this.y}`,m.x,m.y)
    found = true;
    }
}
}
let m = {}// mouse

cText.addEventListener("mousedown",(e)=>{
  drawing = true;
  m = oMousePos(canvas, e);
  let circle = new Circle(m.x,m.y)
  circles.push(circle);
})

cText.addEventListener("mouseup",(e)=>{
  drawing = false; 
  
})


cText.addEventListener("mousemove",(e)=>{
  m = oMousePos(canvas, e);
  found = false;
  if(drawing){
    let circle = circles[circles.length-1];//the last circle in the circles arrey
    circle.updateR(m); 
  }
  ctx.clearRect(0,0, cw,ch);
  ctxText.clearRect(0,0,cw,ch) 
  circles.map((c) => {c.paint();}); 
  for(let i = circles.length-1; i >=0 ; i--){
    circles[i].label(m);
    if(found){break;}
  }
  
  
})


function oMousePos(canvas, evt) {
  var ClientRect = canvas.getBoundingClientRect();
  return { //objeto
    x: Math.round(evt.clientX - ClientRect.left),
    y: Math.round(evt.clientY - ClientRect.top)
  }
}

function dist(p1, p2) {
  let dx = p2.x - p1.x;
  let dy = p2.y - p1.y;
  return Math.sqrt(dx * dx + dy * dy);
}
canvas{border:1px solid;position:absolute; top:0; left:0;}
#scrollParent{position:relative;}
<div id="scrollParent">
  <!-- actual canvas that is visible -->
  <canvas width="640" height="360"></canvas>
  <canvas width="640" height="360" id="text"></canvas>

</div>

Я обновил код на основе комментария @HelderSepu

ВТОРОЕ ОБНОВЛЕНИЕ на основе второго сообщения от @HelderSepu. Он хочет видеть «несколько сообщений, но не перекрывать их».

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
let cw = canvas.width = 640;
let ch = canvas.height = 360;

let text = "";

const cText = document.querySelector("#text");
const ctxText = cText.getContext("2d");
cText.width = 640;
cText.height = 360;
ctxText.font="1em Verdana";


let drawing = false;

let circles = []


class Circle{
  constructor(x,y){
    this.x = x; 
    this.y = y;
    this.r = 0;
  }
  
  updateR(m) {
    this.r = dist(this,m);
  }
  draw(){ 
     ctx.beginPath();
     ctx.arc(this.x,this.y,this.r,0,2*Math.PI);
   }
  paint(){
    ctx.fillStyle = "green";
    ctx.strokeStyle = "black";
    this.draw();
    ctx.stroke();
    ctx.fill();
  }
  
  label(m){
    this.draw();
    if (ctx.isPointInPath(m.x, m.y)) {
    this.text = `[${this.x},${this.y}]`
  }else{
    this.text = "";
  }
}
}
let m = {}// mouse

cText.addEventListener("mousedown",(e)=>{
  drawing = true;
  m = oMousePos(canvas, e);
  let circle = new Circle(m.x,m.y)
  circles.push(circle);
})

cText.addEventListener("mouseup",(e)=>{
  drawing = false; 
  
})


cText.addEventListener("mousemove",(e)=>{
  m = oMousePos(canvas, e);
  
  if(drawing){
    let circle = circles[circles.length-1];//the last circle in the circles arrey
    circle.updateR(m); 
  }
  ctx.clearRect(0,0, cw,ch);
  ctxText.clearRect(0,0,cw,ch);
  text="";
  circles.map((c) => {c.paint();c.label(m);}); 
  circles.map((c) => {text += c.text;});
  ctxText.fillStyle = "black";
  ctxText.fillText(text,m.x,m.y)
  
})


function oMousePos(canvas, evt) {
  var ClientRect = canvas.getBoundingClientRect();
  return { //objeto
    x: Math.round(evt.clientX - ClientRect.left),
    y: Math.round(evt.clientY - ClientRect.top)
  }
}

function dist(p1, p2) {
  let dx = p2.x - p1.x;
  let dy = p2.y - p1.y;
  return Math.sqrt(dx * dx + dy * dy);
}
canvas{border:1px solid;position:absolute; top:0; left:0;}
#scrollParent{position:relati
<div id="scrollParent">
  <!-- actual canvas that is visible -->
  <canvas width="640" height="360"></canvas>
  <canvas width="640" height="360" id="text"></canvas>

<div id="console"></div>
</div>
2
enxaneta 19 Сен 2018 в 16:08