2016-03-25 3 views
2
<!DOCTYPE html> 
<html> 
<head> 
    <style type="text/css"> 
     #canvasOne 
     { 
      border: 1px solid black;    
     } 
    </style> 
    <script src="http://code.jquery.com/jquery-1.10.2.js" type="text/javascript"></script> 
</head> 
<body> 
    <div align="center"> 
     <canvas id="canvasOne"> 
     </canvas> 
    </div> 

    <script type="text/javascript"> 

     var myCanvas = document.getElementById("canvasOne"); 
     var myContext = myCanvas.getContext("2d"); 

     var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; 

     init(); 

     var numShapes; 
     var shapes; 
     var dragIndex; 
     var dragging; 
     var mouseX; 
     var mouseY; 
     var dragHoldX; 
     var dragHoldY; 
     var timer; 
     var targetX; 
     var targetY; 
     var easeAmount; 
     var bgColor; 
     var nodes; 
     var colorArr; 

     function init() 
     { 
      myCanvas.width = $(window).width() - 200; 
      myCanvas.height = $(window).height() - 200; 

      shapes = []; 
      nodes = ["0;Person;24828760;Alok Kumar;Gorakhpur;#F44336;28", 
        "0;Suspect;04/Dec/2016;4;Suman_Biswas;#3F51B5;20","1;Rule;4;Apparent Means;3 Parameter;#EEFF41;20", 
        "0;Policy;36QA649749;In-Force;Quarterly;#FF9800;20","3;Product;Pension;Saral Pension;SRPEN;#795548;20","3;Payment;Cheque;Realized;Lucknow;#0091EA;20", 
        "0;Policy;162348873;Lapsed;Quarterly;#FF9800;20","6;Product;Pension;Life-Long Pension;LLPP;#795548;20","6;Payment;Cheque;Realized;Gorakhpur;#0091EA;20", 
        "0;Policy;1EQF178639;Lapsed;Monthly;#FF9800;20","9;Product;Life;Shield;SHIELDA;#795548;20","9;Payment;Demand Draft;Realized;Lucknow;#0091EA;20"];           

      numShapes = nodes.length; 

      makeShapes(); 

      drawScreen();  

      myCanvas.addEventListener("mousedown", mouseDownListener, false); 
     } 

     //drawing 
     function makeShapes() 
     { 
      var tempX; 
      var tempY; 

      for(var i = 0; i < numShapes; i++) 
      {         
       var centerX = myCanvas.width/2; 
       var centerY = myCanvas.height/2; 

       var nodeColor = nodes[i].split(";")[5]; 

       var nodeRadius = nodes[i].split(";")[6]; 

       var nodeConnect = nodes[i].split(";")[0]; 

       if(i == 0)//center of circle 
       {     
        tempX = centerX 
        tempY = centerY;      
       } 
       else 
       { 
        //tempX = Math.random() * (myCanvas.width - tempRadius); 
        //tempY = Math.random() * (myCanvas.height - tempRadius); 

        //var x = x0 + r * Math.cos(2 * Math.PI * i/items); 
        //var y = y0 + r * Math.sin(2 * Math.PI * i/items); 


        //250 is the distance from center node to outside nodes it can be actual radius in degrees 
        tempX = shapes[nodeConnect].x + 300 * Math.cos(2 * Math.PI * i/numShapes); 
        tempY = shapes[nodeConnect].y + 300 * Math.sin(2 * Math.PI * i/numShapes);          
       } 

       tempShape = {x: tempX, y: tempY, rad: nodeRadius, color: nodeColor, text: nodes[i]}; 

       shapes.push(tempShape); 
      }  
     } 

     //drawing both shape (line and circle) and screen 

     function drawScreen() 
     { 
      myContext.fillStyle = "#ffffff"; 
      myContext.fillRect(0, 0, myCanvas.width, myCanvas.height); 
      drawShapes(); 
     } 

     function drawShapes() 
     {  
      //line 
      for(var i = 1; i < numShapes; i++) 
      { 
       myContext.beginPath(); 
       myContext.strokeStyle = "#B2B19D"; 

       var nodeConnect = nodes[i].split(";")[0]; 

       myContext.moveTo(shapes[nodeConnect].x, shapes[nodeConnect].y); 
       myContext.lineTo(shapes[i].x, shapes[i].y); 
       myContext.stroke(); 
      } 

      //circle   
      for(var i = 0; i < numShapes; i++) 
      {       
       myContext.fillStyle = shapes[i].color; 
       myContext.beginPath(); 
       myContext.arc(shapes[i].x, shapes[i].y, shapes[i].rad, 0, 2*Math.PI, false);     
       myContext.closePath(); 
       myContext.fill(); 
      } 

      //text 
      for(var i = 0; i < numShapes; i++) 
      { 
       myContext.beginPath();   
       myContext.font = '10pt Arial'; 
       myContext.fillStyle = 'black'; 
       var textarr = shapes[i].text.split(";"); 

       myContext.fillText(textarr[1], shapes[i].x + 30, shapes[i].y - 24); 
       /*myContext.fillText(textarr[2], shapes[i].x + 30, shapes[i].y + 1); 
       myContext.fillText(textarr[3], shapes[i].x + 30, shapes[i].y + 22); 
       myContext.fillText(textarr[4], shapes[i].x + 30, shapes[i].y + 44);*/   
       myContext.closePath(); 
       myContext.fill(); 
      } 


     } 

     //animation 

     function mouseDownListener(evt) 
     { 
      var highestIndex = -1; 

      var bRect = myCanvas.getBoundingClientRect(); 
      mouseX = (evt.clientX - bRect.left) * (myCanvas.width/bRect.width); 
      mouseY = (evt.clientY - bRect.top) * (myCanvas.height/bRect.height); 

      for(var i = 0; i < numShapes; i++) 
      { 
       if(hitTest(shapes[i], mouseX, mouseY)) 
       { 
        dragging = true; 
        if(i > highestIndex) 
        { 
         dragHoldX = mouseX - shapes[i].x; 
         dragHoldY = mouseY - shapes[i].y; 
         highestIndex = i; 
         dragIndex = i; 
        }    
       } 
      } 

      if(dragging) 
      { 
       window.addEventListener("mousemove", mouseMoveListener, false); 
      } 

      myCanvas.removeEventListener("mousedown", mouseDownListener, false); 
      window.addEventListener("mouseup", mouseUpListener, false); 

      if(evt.preventDefault) 
      { 
       evt.preventDefault; 
      } 

      return false; 
     } 

     function mouseMoveListener(evt) 
     { 
      var shapeRad = shapes[dragIndex].rad; 

      var minX = shapeRad; 
      var maxX = myCanvas.width - shapeRad; 

      var minY = shapeRad; 
      var maxY = myCanvas.height - shapeRad; 

      //get mouse position correctly 
      var bRect = myCanvas.getBoundingClientRect(); 
      mouseX = (evt.clientX - bRect.left)*(myCanvas.width/bRect.width); 
      mouseY = (evt.clientY - bRect.top)*(myCanvas.height/bRect.height); 

      //clamp x and y position to prevent object from dragging outside canvas 
      posX = mouseX - dragHoldX; 
      posX = (posX < minX) ? minX : ((posX > maxX) ? maxX : posX); 
      posY = mouseY - dragHoldY;  
      posY = (posY < minY) ? minY : ((posY > maxY) ? maxY : posY); 

      shapes[dragIndex].x = posX; 
      shapes[dragIndex].y = posY; 

      drawScreen();  
     } 

     function mouseUpListener(evt) 
     { 
      myCanvas.addEventListener("mousedown", mouseDownListener, false); 
      window.removeEventListener("mouseup", mouseUpListener, false); 

      if(dragging) 
      { 
       dragging = false;         
       window.removeEventListener("mousemove", mouseMoveListener, false);   
      } 
     } 

     function hitTest(shape, mx, my) 
     { 
      var dx = mx - shape.x; 
      var dy = my - shape.y; 

      return(dx * dx + dy * dy < shape.rad * shape.rad); 
     } 

    </script> 
</body> 
</html> 
  1. Следующий холст анимации создает узлы и ребра. Однако из-за для ограничения пространства некоторые узлы не видны из-за холста высота и ширина. Даже добавление переполнения css в canvas dosen't help как Я не могу прокручивать.
+2

контекст canvas не имеет встроенного метода прокрутки, либо реализуйте его самостоятельно, используя ['translate'] (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/ перевести), ['transform'] (https: //developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform) или ['setTransform'] (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setTransform) или установите свой холст настолько большой, насколько вам нужно, и оберните его другим элементом, который будет иметь требуемые экранные размеры, и добавьте к этому элементу свойство переполнения css. – Kaiido

+0

Вы можете исправить вышеуказанный письменный код или примеры примеров – Vineet

ответ

1

Таким образом, ваши рисунки узлов не подходят для размера холста?

Вы можете легко «сжать» свой контент, чтобы он соответствовал видимому холсту всего за 1 команду!

Команда context.scale(horizontalRescale,verticalRescale) сжимает каждый следующий чертеж с помощью указанного горизонтального разреза & verticalRescale процентов.

Важное примечание: Вы должны сделать horizontalRescale, verticalRescale, то же значение или ваш контент будет искажен.

Хорошая вещь об использовании context.scale заключается в том, что вам не нужно менять какой-либо код, который рисует ваши узлы ... canvas автоматически масштабирует все эти узлы для вас.

Например, этот код будет уменьшить ваши узлы до 80% от их первоначального размера:

var downscaleFactor= 0.80; 

context.scale(downscaleFactor, downscaleFactor); 

Вместо того, чтобы через ваши 200+ строк кода, я оставляю вам рассчитать downscaleFactor.

+0

Он работает. Thanx. Помимо опции масштабирования. Можно ли перетаскивать холст горизонтально и вертикально, чтобы пользователь мог видеть все возможные узлы, просто прокручивая или, если я нажимаю на верхний узел, все подключенные к нему узлы будут видны, а холст автоматически прокрутится до этой позиции – Vineet

+0

Да, авто -прокрутка возможна путем перерисовки всего холста, но потянув его горизонтально и вертикально, пока не будут видны нужные вам узлы. Так же, как «context.scale» в моем ответе, вы можете использовать 'context.translate (horizontalOffset, verticalOffset)', чтобы вывести нужные вам узлы. Нет никакой гарантии, что все ваши нужные узлы будут соответствовать размеру доступного холста, поэтому вам все равно придется выполнять «context.scale». Удачи с вашим проектом! :-) – markE

9

<canvas> Контекст не имеет встроенного метода прокрутки.

У вас есть несколько способов обойти это ограничение.

Первый, как в ответе @ markE, масштабирует матрицу вашего контекста так, чтобы ваши рисунки вписывались в требуемое пространство. Вы также можете реорганизовать свой код, чтобы все координаты были относительно размера холста.
Таким образом, вам не нужны полосы прокрутки, и все ваши рисунки будут просто масштабированы соответствующим образом, что является желательным поведением в большинстве распространенных случаев.


Но если вам действительно нужно иметь некоторую функцию прокрутки, вот несколько способов:


Самый простой и наиболее рекомендуемый один: пусть браузер обрабатывать его.

Вам нужно будет установить размер вашего холста максимум на ваши рисунки и обернуть его другим прокруткой. Установив в контейнере свойство css 10, появятся наши полосы прокрутки, и у нас есть функция прокрутки.

В следующем примере холст имеет ширину 5000 пикселей и контейнер 200 пикселей.

var ctx = canvas.getContext('2d'); 
 
ctx.textAlign = 'center'; 
 
for (var w = 0; w < canvas.width; w += 100) { 
 
    for (var h = 0; h < canvas.height; h += 100) { 
 
    ctx.fillText(w + ',' + h, w, h); 
 
    } 
 
}
#container { 
 
    width: 200px; 
 
    height: 200px; 
 
    overflow: auto; 
 
    border: 1px solid; 
 
}
<div id="container"> 
 
    <canvas id="canvas" height="5000" width="5000"></canvas> 
 
</div>

Основные преимущества:

  • легко реализовать.
  • пользователей используют эти полосы прокрутки.

Основные предостережений:

  • Вы ограничены canvas maximum sizes.
  • Если ваш холст анимирован, вы также рисуете для каждой части кадра холста, которые не видны.
  • У вас есть небольшой контроль над просмотром прокрутки, и вам все равно придется реализовать функцию перетаскивания для прокрутки для настольных браузеров.

Второе решение, чтобы реализовать эту функцию самостоятельно, используя холст преобразования методов: в частности, translate, transform и setTransform.

Вот пример:

var ctx = canvas.getContext('2d'); 
 

 
var app = {}; 
 
// the total area of our drawings, can be very large now 
 
app.WIDTH = 5000; 
 
app.HEIGHT = 5000; 
 

 
app.draw = function() { 
 
    // reset everything (clears the canvas + transform + fillStyle + any other property of the context) 
 
    canvas.width = canvas.width; 
 

 
    // move our context by the inverse of our scrollbars' left and top property 
 
    ctx.setTransform(1, 0, 0, 1, -app.scrollbars.left, -app.scrollbars.top); 
 

 
    ctx.textAlign = 'center'; 
 
    // draw only the visible area 
 
    var visibleLeft = app.scrollbars.left; 
 
    var visibleWidth = visibleLeft + canvas.width; 
 
    var visibleTop = app.scrollbars.top 
 
    var visibleHeight = visibleTop + canvas.height; 
 

 
    // you probably will have to make other calculations than these ones to get your drawings 
 
    // to draw only where required 
 
    for (var w = visibleLeft; w < visibleWidth + 50; w += 100) { 
 
    for (var h = visibleTop; h < visibleHeight + 50; h += 100) { 
 
     var x = Math.round((w)/100) * 100; 
 
     var y = Math.round((h)/100) * 100; 
 
     ctx.fillText(x + ',' + y, x, y); 
 
    } 
 
    } 
 

 
    // draw our scrollbars on top if needed 
 
    app.scrollbars.draw(); 
 
} 
 

 
app.scrollbars = function() { 
 
    var scrollbars = {}; 
 
    // initial position 
 
    scrollbars.left = 0; 
 
    scrollbars.top = 0; 
 
    // a single constructor for both horizontal and vertical \t 
 
    var ScrollBar = function(vertical) { 
 
    var that = { 
 
     vertical: vertical 
 
    }; 
 

 
    that.left = vertical ? canvas.width - 10 : 0; 
 
    that.top = vertical ? 0 : canvas.height - 10; 
 
    that.height = vertical ? canvas.height - 10 : 5; 
 
    that.width = vertical ? 5 : canvas.width - 10; 
 
    that.fill = '#dedede'; 
 

 
    that.cursor = { 
 
     radius: 5, 
 
     fill: '#bababa' 
 
    }; 
 
    that.cursor.top = vertical ? that.cursor.radius : that.top + that.cursor.radius/2; 
 
    that.cursor.left = vertical ? that.left + that.cursor.radius/2 : that.cursor.radius; 
 

 
    that.draw = function() { 
 
     if (!that.visible) { 
 
     return; 
 
     } 
 
     // remember to reset the matrix 
 
     ctx.setTransform(1, 0, 0, 1, 0, 0); 
 
     // you can give it any shape you like, all canvas drawings operations are possible 
 
     ctx.fillStyle = that.fill; 
 
     ctx.fillRect(that.left, that.top, that.width, that.height); 
 
     ctx.beginPath(); 
 
     ctx.arc(that.cursor.left, that.cursor.top, that.cursor.radius, 0, Math.PI * 2); 
 
     ctx.fillStyle = that.cursor.fill; 
 
     ctx.fill(); 
 
    }; 
 
    // check if we're hovered 
 
    that.isHover = function(x, y) { 
 
     if (x >= that.left - that.cursor.radius && x <= that.left + that.width + that.cursor.radius && 
 
     y >= that.top - that.cursor.radius && y <= that.top + that.height + that.cursor.radius) { 
 
     // we are so record the position of the mouse and set ourself as the one hovered 
 
     scrollbars.mousePos = vertical ? y : x; 
 
     scrollbars.hovered = that; 
 
     that.visible = true; 
 
     return true; 
 
     } 
 
     // we were visible last call and no wheel event is happening 
 
     else if (that.visible && !scrollbars.willHide) { 
 
     that.visible = false; 
 
     // the app should be redrawn 
 
     return true; 
 
     } 
 
    } 
 

 
    return that; 
 
    }; 
 

 
    scrollbars.horizontal = ScrollBar(0); 
 
    scrollbars.vertical = ScrollBar(1); 
 

 
    scrollbars.hovered = null; 
 
    scrollbars.dragged = null; 
 
    scrollbars.mousePos = null; 
 
    // check both of our scrollbars 
 
    scrollbars.isHover = function(x, y) { 
 
    return this.horizontal.isHover(x, y) || this.vertical.isHover(x, y); 
 
    }; 
 
    // draw both of our scrollbars 
 
    scrollbars.draw = function() { 
 
    this.horizontal.draw(); 
 
    this.vertical.draw(); 
 
    }; 
 
    // check if one of our scrollbars is visible 
 
    scrollbars.visible = function() { 
 
    return this.horizontal.visible || this.vertical.visible; 
 
    }; 
 
    // hide it... 
 
    scrollbars.hide = function() { 
 
    // only if we're not using the mousewheel or dragging the cursor 
 
    if (this.willHide || this.dragged) { 
 
     return; 
 
    } 
 
    this.horizontal.visible = false; 
 
    this.vertical.visible = false; 
 
    }; 
 

 
    // get the area's coord relative to our scrollbar 
 
    var toAreaCoord = function(pos, scrollBar) { 
 
    var sbBase = scrollBar.vertical ? scrollBar.top : scrollBar.left; 
 
    var sbMax = scrollBar.vertical ? scrollBar.height : scrollBar.width; 
 
    var areaMax = scrollBar.vertical ? app.HEIGHT - canvas.height : app.WIDTH - canvas.width; 
 

 
    var ratio = (pos - sbBase)/(sbMax - sbBase); 
 

 
    return areaMax * ratio; 
 
    }; 
 

 
    // get the scrollbar's coord relative to our total area 
 
    var toScrollCoords = function(pos, scrollBar) { 
 
    var sbBase = scrollBar.vertical ? scrollBar.top : scrollBar.left; 
 
    var sbMax = scrollBar.vertical ? scrollBar.height : scrollBar.width; 
 
    var areaMax = scrollBar.vertical ? app.HEIGHT - canvas.height : app.WIDTH - canvas.width; 
 

 
    var ratio = pos/areaMax; 
 

 
    return ((sbMax - sbBase) * ratio) + sbBase; 
 
    } 
 

 
    scrollbars.scroll = function() { 
 
     // check which one of the scrollbars is active 
 
     var vertical = this.hovered.vertical; 
 
     // until where our cursor can go 
 
     var maxCursorPos = this.hovered[vertical ? 'height' : 'width']; 
 
     var pos = vertical ? 'top' : 'left'; 
 
     // check that we're not out of the bounds 
 
     this.hovered.cursor[pos] = this.mousePos < 0 ? 0 : 
 
     this.mousePos > maxCursorPos ? maxCursorPos : this.mousePos; 
 

 
     // seems ok so tell the app we scrolled 
 
     this[pos] = toAreaCoord(this.hovered.cursor[pos], this.hovered); 
 
     // redraw everything 
 
     app.draw(); 
 
    } 
 
    // because we will hide it after a small time 
 
    scrollbars.willHide; 
 
    // called by the wheel event 
 
    scrollbars.scrollBy = function(deltaX, deltaY) { 
 
    // it's not coming from our scrollbars 
 
    this.hovered = null; 
 
    // we're moving horizontally 
 
    if (deltaX) { 
 
     var newLeft = this.left + deltaX; 
 
     // make sure we're in the bounds 
 
     this.left = newLeft > app.WIDTH - canvas.width ? app.WIDTH - canvas.width : newLeft < 0 ? 0 : newLeft; 
 
     // update the horizontal cursor 
 
     this.horizontal.cursor.left = toScrollCoords(this.left, this.horizontal); 
 
     // show our scrollbar 
 
     this.horizontal.visible = true; 
 
    } 
 
    if (deltaY) { 
 
     var newTop = this.top + deltaY; 
 
     this.top = newTop > app.HEIGHT - canvas.height ? app.HEIGHT - canvas.height : newTop < 0 ? 0 : newTop; 
 
     this.vertical.cursor.top = toScrollCoords(this.top, this.vertical); 
 
     this.vertical.visible = true; 
 
    } 
 
    // if we were called less than the required timeout 
 
    clearTimeout(this.willHide); 
 
    this.willHide = setTimeout(function() { 
 
     scrollbars.willHide = null; 
 
     scrollbars.hide(); 
 
     app.draw(); 
 
    }, 500); 
 
    // redraw everything 
 
    app.draw(); 
 
    }; 
 

 
    return scrollbars; 
 
}(); 
 

 
var mousedown = function(e) { 
 
    // tell the browser we handle this 
 
    e.preventDefault(); 
 
    // we're over one the scrollbars 
 
    if (app.scrollbars.hovered) { 
 
    // new promotion ! it becomes the dragged one 
 
    app.scrollbars.dragged = app.scrollbars.hovered; 
 
    app.scrollbars.scroll(); 
 
    } 
 
}; 
 

 
var mousemove = function(e) { 
 
    // check the coordinates of our canvas in the document 
 
    var rect = canvas.getBoundingClientRect(); 
 
    var x = e.clientX - rect.left; 
 
    var y = e.clientY - rect.top; 
 
    // we're dragging something 
 
    if (app.scrollbars.dragged) { 
 
    // update the mouse position 
 
    app.scrollbars.mousePos = app.scrollbars.dragged.vertical ? y : x; 
 
    app.scrollbars.scroll(); 
 
    } else if (app.scrollbars.isHover(x, y)) { 
 
    // something has changed, redraw to show or hide the scrollbar 
 
    app.draw(); 
 
    } 
 
    e.preventDefault(); 
 
}; 
 
var mouseup = function() { 
 
    // we dropped it 
 
    app.scrollbars.dragged = null; 
 
}; 
 

 
var mouseout = function() { 
 
    // we're out 
 
    if (app.scrollbars.visible()) { 
 
    app.scrollbars.hide(); 
 
    app.scrollbars.dragged = false; 
 
    app.draw(); 
 
    } 
 
}; 
 

 
var mouseWheel = function(e) { 
 
    e.preventDefault(); 
 
    app.scrollbars.scrollBy(e.deltaX, e.deltaY); 
 
}; 
 

 
canvas.addEventListener('mousemove', mousemove); 
 
canvas.addEventListener('mousedown', mousedown); 
 
canvas.addEventListener('mouseup', mouseup); 
 
canvas.addEventListener('mouseout', mouseout); 
 
canvas.addEventListener('wheel', mouseWheel); 
 

 
range.onchange = function() { 
 
    app.WIDTH = app.HEIGHT = this.value; 
 
    app.scrollbars.left = 0; 
 
    app.scrollbars.top = 0; 
 
    app.draw(); 
 
}; 
 

 
// an initial drawing 
 
app.draw();
canvas {border: 1px solid;} 
 
span{font-size: .8em;}
<canvas id="canvas" width="200" height="150"></canvas> 
 
<span> 
 
    change the total area size 
 
    <input type="range" min="250" max="5000000" steps="250" value="5000" id="range" /> 
 
</span>

Основные преимущества:

  • нет ограничения на размер вашей области рисования.
  • вы можете настроить свои полосы прокрутки по своему усмотрению.
  • Вы можете управлять, когда полосы прокрутки включены или нет.
  • вы можете легко получить видимую область.

Основные предостережений:

  • немного больше кода, чем решение CSS ...
  • нет на самом деле, это не очень много кода ...

A third way Я написал некоторое время назад для другого вопроса, воспользовавшегося возможностью рисовать другой холст с помощью ctx.drawImage(). У этого есть свои собственные предостережения и преимущества, поэтому я позволил вам выбрать тот, который вам нужен, но на этом последнем также была функция перетаскивания и слайда, которая может быть полезна.

Смежные вопросы