Set two canvas squares to the center of a canvas with HTML5 - javascript

I have two boxes positioned on a canvas that I am trying to center. You can view this on JS fiddle: http://jsfiddle.net/FVU47/5/
My canvas has 1000 height and 1000 width as follows:
<canvas id="myCanvas" width="1000" height="1000" style="border:3px solid #385D8A; outline:1px solid #7592B5; margin-left: 0px; margin-top: 0px; background-color: #B9CDE5"></canvas>
I am then attempting to center the two boxes with the following code, which would place either box1 or box2 in the center of the canvas, depending on whether I click on "Go to Box 1" or "Go to Box 2" (see the bottom of the JSFiddle Result quadrant:
$(document).ready(function(){
$("#box1click").click(function(){
if (rect1.x <= 500) {
positionWidthSet = Math.abs(rect1.x - canvas.width/2) + rect1.x;
}
else{
positionWidthSet = Math.abs(Math.abs(rect1.x - canvas.width/2) + rect1.x)
}
if (rect1.y >= 500) {
positionHeightSet = Math.abs(rect1.y -canvas.height/2);
}
else{
positionHeightSet = Math.abs(Math.abs(rect1.y - canvas.height/2) + rect1.y);
}
positionCanvasContext(positionWidthSet,positionHeightSet);
});
});
$(document).ready(function(){
$("#box2click").click(function(){
if (rect2.x <= 500) {
positionWidthSet = Math.abs(rect2.x - canvas.width/2) + rect2.x;
}
else{
positionWidthSet = Math.abs(Math.abs(rect2.x - canvas.width/2) + rect2.x)
}
if (rect2.y >= 500) {
positionHeightSet = Math.abs(rect2.y -canvas.height/2);
}
else{
positionHeightSet = Math.abs(Math.abs(rect2.y - canvas.height/2) + rect2.y);
}
positionCanvasContext(positionWidthSet,positionHeightSet);
});
});
Currently, clicking on either "Go to Box 1" or "Go to Box 2" does not center the canvas around either Box 1 or Box 2, even though experimenting with my formulas in the console would seem to indicate otherwise.

Here's one way: http://jsfiddle.net/m1erickson/GpMsk/
Put all your rects in an array:
var rects=[];
rects.push({
x: 103,
y: 262,
w: 200,
h: 100,
fillStyle: 'red',
hovered: false
});
rects.push({
x: 484,
y: 170,
w: 200,
h: 100,
fillStyle: 'blue',
hovered: false
});
Create a draw() function that draws all rects in the rects[] array
Draw all rects with a specified x/y offset to their original x/y:
function draw(offsetX,offsetY){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<rects.length;i++){
var r=rects[i];
ctx.fillStyle=r.fillStyle;
ctx.fillRect(r.x+offsetX,r.y+offsetY,r.w,r.h);
}
}
When you click a button, calculate the offsets necessary to pull the specified rectangle to the center of the canvas
Then redraw all rects with the calculated offsets.
var centerX=canvas.width/2;
var centerY=canvas.height/2;
function centerThisRect(rectsIndex){
var r=rects[rectsIndex];
var offsetX=centerX-r.x-r.w/2;
var offsetY=centerY-r.y-r.h/2;
draw(offsetX,offsetY);
}

Related

Exclude edges from participating in the layout

Consider a graph like the one shown below:
I would like to be able to display/hide the red edges (forget that they are hand drawn) shown below when the user clicks a button or similar:
I don't want the red edges to participate in the layout but instead for them to be shown as a kind of overlay. It would be nice if the edges could try to avoid overlapping any nodes in their path, but its definitely not required.
I think if I could set a boolean flag on the edges telling the layout engine to either include or exclude them from the layout setup, it could work. There is a physics parameter on the edge that I can override, but it doesn't seem to help - the edge still participates in the layout.
I could probably also write some scripting which tracks the nodes and draw the red edges in another graph above, but that is specifically what I want to avoid.
When using a hierarchical layout in vis network (options.layout.hierarchical.enabled = true) there doesn't appear to be an option which achieves this. This could however be achieved with an overlay. The question mentions that this isn't desired, but adding it as an option. An example is incorporated into the post below and also at https://jsfiddle.net/7abovhtu/.
In summary the solution places an overlay canvas on top of the vis network canvas. Clicks on the overlay canvas are passed through to the vis network canvas due to the CSS pointer-events: none;. Extra edges are drawn onto the overlay canvas using the positioning of the nodes. Updates to the overlay canvas are triggered by the vis network event afterDrawing which triggers whenever the network changes (dragging, zooming, etc.).
This answer makes use of the closest point to an ellipse calculation provided in the answer https://stackoverflow.com/a/18363333/1620449 to end the lines at the edge of the nodes. This answer also makes use of the function in the answer https://stackoverflow.com/a/6333775/1620449 to draw an arrow on a canvas.
// create an array with nodes
var nodes = new vis.DataSet([
{ id: 1, label: "Node 1" },
{ id: 2, label: "Node 2" },
{ id: 3, label: "Node 3" },
{ id: 4, label: "Node 4" },
{ id: 5, label: "Node 5" },
{ id: 6, label: "Node 6" },
{ id: 7, label: "Node 7" },
]);
// create an array with edges
var edges = new vis.DataSet([
{ from: 1, to: 2 },
{ from: 2, to: 3 },
{ from: 3, to: 4 },
{ from: 3, to: 5 },
{ from: 3, to: 6 },
{ from: 6, to: 7 }
]);
// create an array with extra edges displayed on button press
var extraEdges = [
{ from: 7, to: 5 },
{ from: 6, to: 1 }
];
// create a network
var container = document.getElementById("network");
var data = {
nodes: nodes,
edges: edges,
};
var options = {
layout: {
hierarchical: {
enabled: true,
direction: 'LR',
sortMethod: 'directed',
shakeTowards: 'roots'
}
}
};
var network = new vis.Network(container, data, options);
// Create an overlay for displaying extra edges
var overlayCanvas = document.getElementById("overlay");
var overlayContext = overlayCanvas.getContext("2d");
// Function called to draw the extra edges, called on initial display and
// when the network completes each draw (due to drag, zoom etc.)
function drawExtraEdges(){
// Resize overlay canvas in case the continer has changed
overlayCanvas.height = container.clientHeight;
overlayCanvas.width = container.clientWidth;
// Begin drawing path on overlay canvas
overlayContext.beginPath();
// Clear any existing lines from overlay canvas
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
// Loop through extra edges to draw them
extraEdges.forEach(edge => {
// Gather the necessary coordinates for the start and end shapres
const startPos = network.canvasToDOM(network.getPosition(edge.from));
const endPos = network.canvasToDOM(network.getPosition(edge.to));
const endBox = network.getBoundingBox(edge.to);
// Determine the radius of the ellipse based on the scale of network
// Start and end ellipse are presumed to be the same size
const scale = network.getScale();
const radiusX = ((endBox.right * scale) - (endBox.left * scale)) / 2;
const radiusY = ((endBox.bottom * scale) - (endBox.top * scale)) / 2;
// Get the closest point on the end ellipse to the start point
const endClosest = getEllipsePt(endPos.x, endPos.y, radiusX, radiusY, startPos.x, startPos.y);
// Now we have an end point get the point on the ellipse for the start
const startClosest = getEllipsePt(startPos.x, startPos.y, radiusX, radiusY, endClosest.x, endClosest.y);
// Draw arrow on diagram
drawArrow(overlayContext, startClosest.x, startClosest.y, endClosest.x, endClosest.y);
});
// Apply red color to overlay canvas context
overlayContext.strokeStyle = '#ff0000';
// Make the line dashed
overlayContext.setLineDash([10, 3]);
// Apply lines to overlay canvas
overlayContext.stroke();
}
// Adjust the positioning of the lines each time the network is redrawn
network.on("afterDrawing", function (event) {
// Only draw the lines if they have been toggled on with the button
if(extraEdgesShown){
drawExtraEdges();
}
});
// Add button event to show / hide extra edges
var extraEdgesShown = false;
document.getElementById('extraEdges').onclick = function() {
if(!extraEdgesShown){
if(extraEdges.length > 0){
// Call function to draw extra lines
drawExtraEdges();
extraEdgesShown = true;
}
} else {
// Remove extra edges
// Clear the overlay canvas
overlayContext.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
extraEdgesShown = false;
}
}
//////////////////////////////////////////////////////////////////////
// Elllipse closest point calculation
// https://stackoverflow.com/a/18363333/1620449
//////////////////////////////////////////////////////////////////////
var halfPI = Math.PI / 2;
var steps = 8; // larger == greater accuracy
// calc a point on the ellipse that is "near-ish" the target point
// uses "brute force"
function getEllipsePt(cx, cy, radiusX, radiusY, targetPtX, targetPtY) {
// calculate which ellipse quadrant the targetPt is in
var q;
if (targetPtX > cx) {
q = (targetPtY > cy) ? 0 : 3;
} else {
q = (targetPtY > cy) ? 1 : 2;
}
// calc beginning and ending radian angles to check
var r1 = q * halfPI;
var r2 = (q + 1) * halfPI;
var dr = halfPI / steps;
var minLengthSquared = 200000000;
var minX, minY;
// walk the ellipse quadrant and find a near-point
for (var r = r1; r < r2; r += dr) {
// get a point on the ellipse at radian angle == r
var ellipseX = cx + radiusX * Math.cos(r);
var ellipseY = cy + radiusY * Math.sin(r);
// calc distance from ellipsePt to targetPt
var dx = targetPtX - ellipseX;
var dy = targetPtY - ellipseY;
var lengthSquared = dx * dx + dy * dy;
// if new length is shortest, save this ellipse point
if (lengthSquared < minLengthSquared) {
minX = ellipseX;
minY = ellipseY;
minLengthSquared = lengthSquared;
}
}
return ({
x: minX,
y: minY
});
}
//////////////////////////////////////////////////////////////////////
// Draw Arrow on Canvas Function
// https://stackoverflow.com/a/6333775/1620449
//////////////////////////////////////////////////////////////////////
function drawArrow(ctx, fromX, fromY, toX, toY) {
var headLength = 10; // length of head in pixels
var dX = toX - fromX;
var dY = toY - fromY;
var angle = Math.atan2(dY, dX);
ctx.fillStyle = "red";
ctx.moveTo(fromX, fromY);
ctx.lineTo(toX, toY);
ctx.lineTo(toX - headLength * Math.cos(angle - Math.PI / 6), toY - headLength * Math.sin(angle - Math.PI / 6));
ctx.moveTo(toX, toY);
ctx.lineTo(toX - headLength * Math.cos(angle + Math.PI / 6), toY - headLength * Math.sin(angle + Math.PI / 6));
}
#container {
width: 100%;
height: 80vh;
border: 1px solid lightgray;
position: relative;
}
#network, #overlay {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
#overlay {
z-index: 100;
pointer-events: none;
}
<script src="https://visjs.github.io/vis-network/standalone/umd/vis-network.min.js"></script>
<button id="extraEdges">Toggle Extra Edges</button>
<div id="container">
<div id="network"></div>
<canvas width="600" height="400" id="overlay"></canvas>
</div>
This can be achieved using either the physics or hidden options on the extra edges (those in red). For reference, these options are described in more detail at https://visjs.github.io/vis-network/docs/network/edges.html.
Please note the below options do not work when hierarchical layout is used as set in the Vis Network options options.layout.hierarchical.enabled = true.
Physics - An example of using the physics option is https://jsfiddle.net/6oac73p0. However as you mentioned this may cause overlaps with nodes which have physics enabled. The extra edges are set to dashed in this example to ensure everything is still visible.
Hidden - An example of using the hidden option is https://jsfiddle.net/xfcuvtgk/ and also incorporated into this post below. Edges set to hidden are still part of the physics calculation when the layout is generated, which you mentioned wasn't desired, however this does mean they fit nicely when later displayed.
// create an array with nodes
var nodes = new vis.DataSet([
{ id: 1, label: "Node 1" },
{ id: 2, label: "Node 2" },
{ id: 3, label: "Node 3" },
{ id: 4, label: "Node 4" },
{ id: 5, label: "Node 5" },
]);
// create an array with edges
var edges = new vis.DataSet([
{ from: 1, to: 3 },
{ from: 1, to: 2 },
{ from: 2, to: 4 },
{ from: 2, to: 5 },
{ from: 3, to: 3 },
{ from: 4, to: 5, color: 'red', hidden: true, arrows: 'to', extra: true },
{ from: 3, to: 5, color: 'red', hidden: true, arrows: 'to', extra: true },
{ from: 1, to: 5, color: 'red', hidden: true, arrows: 'to', extra: true }
]);
// create a network
var container = document.getElementById("mynetwork");
var data = {
nodes: nodes,
edges: edges,
};
var options = {};
var network = new vis.Network(container, data, options);
document.getElementById('extraEdges').onclick = function() {
// Extract the list of extra edges
edges.forEach(function(edge){
if(edge.extra){
// Toggle the hidden value
edge.hidden = !edge.hidden;
// Update edge back onto data set
edges.update(edge);
}
});
}
#mynetwork {
width: 600px;
/* Height adjusted for Stack Overflow inline demo */
height: 160px;
border: 1px solid lightgray;
}
<script src="https://visjs.github.io/vis-network/standalone/umd/vis-network.min.js"></script>
<button id="extraEdges">Show/Hide Extra Edges</button>
<div id="mynetwork"></div>

How to flip a rotated image in konvajs

I am trying to flip a group (horizontally) using Konvajs.Following the advice of this post, I am using the scaleX property. This works---mostly. However, it doesn't flip around the center.
function reverse(shape){
var layer = shape.getLayer();
var oldScaleX = shape.attrs.scaleX;
var width = shape.getClientRect().width;
var adjuster = oldScaleX * width;
var startX = shape.attrs.x + adjuster;
var startY = shape.attrs.y;
shape.scaleX(-oldScaleX);
shape.position({x: startX, y: startY});
layer.draw();
};
I tried using the offsetX and offsetY properties like in this post, but it doesn't seem to do anything.
shape.offsetX(shape.width()/2);
shape.offsetY(shape.height()/2);
shape.x(shape.x() - shape.attrs.offsetX);
shape.y(shape.y() - shape.attrs.offsetY);
The shapes will flip initially, but if they are rotated first, they tend to jump around.
Codepen
Based on my function posted in this other question, here is a snippet to rotate a shape around its centre. In this case the shape is a group composed of 2 rects but any shape will work.
// Set up the canvas / stage
var stage = new Konva.Stage({container: 'container', width: 600, height: 200});
var layer = new Konva.Layer({draggable: false});
stage.add(layer);
var shape = new Konva.Group({x: 80, y: 40, width: 60, height: 60 });
var r1 = new Konva.Rect({ x:10, y:10, width: 70, height: 40, fill: 'cyan'})
var r2 = new Konva.Rect({ x:50, y:10, width: 40, height: 100, fill: 'cyan'})
shape.add(r1)
shape.add(r2)
layer.add(shape)
// set the group rotate point. Note - x,y is relative to top-left of stage !
var pos = shape.getClientRect();
RotatePoint(shape, {x: pos.x + pos.width/2, y: pos.y + pos.height/2});
stage.draw();
// This is where the flip happens
var scaleX = 1, inc = -0.2; // set inc = 1 for full flip in one call
function flipShape(){
scaleX = scaleX + inc;
shape.scaleX(scaleX); // and that's it
// fun with colors on front and back of shape
r1.fill(scaleX < 0 ? 'magenta' : 'cyan');
r2.fill(scaleX < 0 ? 'magenta' : 'cyan');
$('#info').html('Set ScaleX(' + scaleX.toFixed(2) + ')'); // What's happening?
layer.draw(); // show the change
inc = (scaleX % 1 === 0 ? -1 * inc : inc); // decide next increment, reversed at 1 & -1
}
$('#flip').on('click', function(e){
flipShape(); // click button - flip shape a bit
})
/*
Set the offset for rotation to the given location and re-position the shape
*/
function RotatePoint(shape, pos){ // where pos = {x: xpos, y: yPos}
var initialPos = shape.getAbsolutePosition();
var moveBy = {x: pos.x - initialPos.x, y: pos.y - initialPos.y};
// offset is relative to initial x,y of shape, so deduct x,y.
shape.offsetX(moveBy.x);
shape.offsetY(moveBy.y);
// reposition x,y because changing offset moves it.
shape.x(initialPos.x + moveBy.x);
shape.y(initialPos.y + moveBy.y);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.5.1/konva.js"></script>
<p>Clck the button to progressively flip a shape using scaleX <button id='flip'>Flip a bit</button> <span id='info'></span></p>
<div id='container' style="position: absolute; top: 0; z-index: -1; display: inline-block; width: 600px, height: 200px; background-color: silver; "></div>

Kineticjs Group Image dragging

I am new to Kinetic js and having issue figuring out how to stop the image from moving outside the boundary which then creates a white space
Here is my code so far
//photo layer
var photoGroup = new Kinetic.Group({ x: layout.photoGroup.x, y: layout.photoGroup.y, draggable: true });
var Photolayer = new Kinetic.Layer();
var cropArea = new Kinetic.Rect({
x: layout.cropAreaRect.x,
y: layout.cropAreaRect.y,
width: layout.cropAreaRect.width,
height: layout.cropAreaRect.height,
fill: "white",
listening: false
});
Photolayer.add(cropArea);
Photolayer.add(photoGroup);
stage.add(Photolayer);
Here is a working code snippet illustrating a dragBoundFunc().
The gold rect is the area we intend to restrict the drag within. The blue rect shows the area we compute - different from the gold because we use the topleft of the draggable as the basis for our maths and we have to account for its own width and height. The red block could be an image or any Konvajs element.
Drag the red block!
// add a stage
var s = new Konva.Stage({
container: 'container',
width: 800,
height: 600
});
// add a layer
var l = new Konva.Layer();
s.add(l);
// Add a green rect to the LAYER just to show boundary of the stage.
var green = new Konva.Rect({stroke: 'lime', width: 800, height: 600, x: 0, y: 0});
l.add(green);
// Add a gold rect to the LAYER just to give some visual feedback on intended drag limits
var gold = new Konva.Rect({stroke: 'gold', width: 400, height: 200, x: 55, y: 55});
l.add(gold);
// Add a red rect to act as our draggable
var red = new Konva.Rect({fill: 'red', stroke: 'red', width: 40, height: 50, x: 65, y: 65, draggable: true,
dragBoundFunc: function(pos) {
var newX = pos.x;
if (newX < minX){ newX = minX};
if (newX > maxX){ newX = maxX};
var newY = pos.y;
if (newY < minY){ newY = minY};
if (newY > maxY){ newY = maxY};
$("#info").html('Info: Pos=(' + newX + ', ' + newY + ') range X=' + minX + ' - ' + maxX + ' Y=' + minY + ' - ' + maxY);
return {
x: newX,
y: newY
}
}
});
l.add(red);
// calculate the drag boundary once for performance - we need to have the draggable element size for this !
var goldPos = gold.getAbsolutePosition()
var minX = goldPos.x;
var maxX = goldPos.x + gold.width() - red.width();
var minY = goldPos.y;
var maxY = goldPos.y + gold.height() - red.height();
// Add a blue rect to the LAYER just show the computed drag limits - note the subtraction of the draggable element dimensions from maxX & Y. Note the 1px adjustment is to avoid overlapping the gold rect in the demo and is not required for live.
var blue = new Konva.Rect({stroke: 'blue', opacity: 0.2, width: 399 - red.width(), height: 199 - red.height(), x: 56, y: 56});
l.add(blue);
// bring red back to top so we can drag it
red.moveToTop();
l.draw(); // redraw the layer it all sits on.
#container {
border: 1px solid #ccc;
}
#info {
height: 20px;
border-bottom: 1px solid #ccc;
}
#hint {
font-style: italic;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.3/konva.min.js"></script>
<body>
<div id='hint'>Hint: green is stage, gold is intended drag limit, blue is computed drag limit.<br/>Drag the red block!</div>
<div id='info'>Info:</div>
<div id="container"></div>
</body>
As an example of dragBoundFunc:
const dragRect = new Konva.Rect({
x: window.innerWidth / 2 - 50,
y: window.innerHeight / 2 - 50,
width: 100,
height: 100,
fill: 'green',
draggable: true,
dragBoundFunc: (pos) => {
const leftBound = cropRect.x();
const rightBound = cropRect.x() + cropRect.width() - dragRect.width();
pos.x = Math.max(leftBound, Math.min(rightBound, pos.x));
const topBound = cropRect.y();
const bottomBound = cropRect.y() + cropRect.height() - dragRect.height();
pos.y = Math.max(topBound, Math.min(bottomBound, pos.y));
return pos;
}
});
Demo: http://jsbin.com/jilagadeqa/1/edit?js,output

Drag object programmatically

I have 3 rectangles on top of eachother like so:
new Fabric.Rect({
width: 200 - index * 30,
height: 20,
hasBorders: false,
selectable: false,
hasControls: false
});
and then I have a click event which detects clicks NEAR (not on the rectangle) the rectangles and makes the top rectangle (highest one of the stack of 3) selectable (to drag it):
var first = this.first().shape; // Fabric.Rect
canvas.setActiveObject(first);
However, this does not set the object on the cursor, to drag the object.
How can I make it so the object is selected, immediately moved to the cursor and enabled to be dragged around once the click event fires?
This should get you fairly close, if I understood you correctly.
Click anywhere inside the black square of the canvas and outside the red object.
var canvas = new fabric.Canvas('c', {
selection: false,
});
var rectangle = new fabric.Rect({
fill: 'red',
left: 10,
top: 10,
width: 100,
height: 100 //,
//padding: 50
});
canvas.on('mouse:down', function(env) {
var x = env.e.offsetX;
var y = env.e.offsetY;
rectangle.setLeft(x - rectangle.width / 2);
rectangle.setTop(y - rectangle.height / 2);
canvas.setActiveObject(rectangle);
rectangle.setCoords();
canvas.renderAll();
canvas.on('mouse:move', function(env) {
var x = env.e.offsetX;
var y = env.e.offsetY;
rectangle.setLeft(x - rectangle.width / 2);
rectangle.setTop(y - rectangle.height / 2);
rectangle.setCoords();
canvas.renderAll();
});
canvas.on('mouse:up', function(env) {
canvas.off('mouse:move');
});
});
canvas.add(rectangle);
canvas.renderAll();
#c {
border: 1px solid black;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>
<canvas id="c" width="200" height="200"></canvas>
I intentionally commented out padding on the rectangle, but left it in the code, in case you wanted to use that as your NEAR logic instead of what you already have. If you do choose to use padding as your NEAR logic you will then need to change the on canvas mouse:down event to an on canvas object:selected event.
Also, if you haven't done so already, you might like to take a close look at this Objects Bounding Rectangles example for some further ideas for your NEAR logic, http://fabricjs.com/bounding-rectangle.
Any-who, let me know how you get on, matey!

Dynamically flexible path between two points in SVG

Hi can some one help me bend path like here
here u can see it in action (it's almost what i need, but it on canvas)
QUESTION
how i can calculate it?
which formula describes this
and how correctly to describe the parameters 'd' of path
here's my code (maybe it needs some improvements?)
var app = angular.module('app', []);
app.controller("ctrl", function ($scope) {
var lineGraph = d3.select("#container").append("svg:svg").attr("width", '100%').attr("height", '100%');
$scope.linesArr = [];
$scope.blocksArr = [{
id: 0,
x: 0,
y: 0,
lineToID: [2]
},{
id: 1,
x: 0,
y: 0,
lineToID: [0,2]
},{
id: 2,
x: 0,
y: 0,
lineToID: []
}];
$scope.createLines = function(){
for(var i = 0; i < $scope.blocksArr.length; i++){
if($scope.blocksArr[i].lineToID.length){
for(var j = 0; j < $scope.blocksArr[i].lineToID.length; j++){
$scope.linesArr[$scope.blocksArr[i].id + ":"+j] = (lineGraph.append("svg:line"));
}
}
}
};
$scope.createLines();
$scope.checkPoints = function(){
for(var i = 0; i < $scope.blocksArr.length; i++){
$scope.blocksArr[i].x = parseInt(document.querySelector('#b' + i).style.left) + (document.querySelector('#b' + i).offsetWidth / 2);
$scope.blocksArr[i].y = parseInt(document.querySelector('#b' + i).style.top) + (document.querySelector('#b' + i).offsetHeight / 2);
if($scope.blocksArr[i].lineToID.length){
for(var j = 0; j < $scope.blocksArr[i].lineToID.length; j++){
$scope.linesArr[$scope.blocksArr[i].id+":"+j]
.attr("x1", $scope.blocksArr[$scope.blocksArr[i].id].x)
.attr("y1", $scope.blocksArr[$scope.blocksArr[i].id].y)
.attr("x2", $scope.blocksArr[$scope.blocksArr[i].lineToID[j]].x)
.attr("y2", $scope.blocksArr[$scope.blocksArr[i].lineToID[j]].y)
.style("stroke", "rgb(6,120,155)");
//console.log();
}
}
}
};
$scope.dragOptions = {
start: function(e) {
//console.log("STARTING");
},
drag: function(e) {
$scope.checkPoints();
//console.log("DRAGGING");
},
stop: function(e) {
//console.log("STOPPING");
},
container: 'container'
}
});
app.directive('ngDraggable', function($document) {
return {
restrict: 'A',
scope: {
dragOptions: '=ngDraggable'
},
link: function(scope, elem, attr) {
var startX, startY, x = 0, y = 0,
start, stop, drag, container;
var width = elem[0].offsetWidth,
height = elem[0].offsetHeight;
// Obtain drag options
if (scope.dragOptions) {
start = scope.dragOptions.start;
drag = scope.dragOptions.drag;
stop = scope.dragOptions.stop;
var id = scope.dragOptions.container;
if (id) {
container = document.getElementById(id).getBoundingClientRect();
}
}
// Bind mousedown event
elem.on('mousedown', function(e) {
e.preventDefault();
startX = e.clientX - elem[0].offsetLeft;
startY = e.clientY - elem[0].offsetTop;
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
if (start) start(e);
});
// Handle drag event
function mousemove(e) {
y = e.clientY - startY;
x = e.clientX - startX;
setPosition();
if (drag) drag(e);
}
// Unbind drag events
function mouseup(e) {
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
if (stop) stop(e);
}
// Move element, within container if provided
function setPosition() {
if (container) {
if (x < container.left) {
x = container.left;
} else if (x > container.right - width) {
x = container.right - width;
}
if (y < container.top) {
y = container.top;
} else if (y > container.bottom - height) {
y = container.bottom - height;
}
}
elem.css({
top: y + 'px',
left: x + 'px'
});
}
}
}
})
html,body, #container{
height: 100%;
margin: 0;
}
.box{
position: absolute;
width: 100px;
height: 30px;
line-height: 30px;
border: 1px solid #c07f7f;
text-align: center;
background: #f3f4ff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-controller="ctrl" ng-app="app" id="container">
<div class="box" id="b{{$index}}" ng-repeat="i in blocksArr" ng-draggable='dragOptions' ng-style="{top: blocksArr[$index].y, left: blocksArr[$index].x}">{{$index}}</div>
</div>
Guessing, I'm thinking that what you want is to:
Show two points on screen.
Calculate an axis-aligned right triangle that touches those points.
Draw a triangle for the fill and colored lines for the edges of the triangles.
Allow the user to use the mouse to click and drag the points to new locations.
Dynamically update the right triangle based on those points.
It is unclear which part of the above you are having trouble with (other than, perhaps, "all of it"). In general, computer programming is about identifying what you want to do, breaking it down into simple steps (as I did above) and then working on those steps one at a time.
Can you calculate two 'random' points on screen? (Hint: Math.random() might be appropriate, or else you can just pick two fixed starting locations.)
Can you draw two points on screen? (Hint: You can use a SVG <circle> and adjust the cx and cy attributes.)
Can you calculate where the third point should be? (Hint: one way is to use the 'x' value of one point and the 'y' value of the other point.)
Can you draw a filled triangle between these points? (Hint: an easy way is to use an SVG <polygon> and adjust the points attribute.)
Can you draw three lines for the edges? (Hint: use <line> or <polyline> elements that are later in the document than the <polygon> so that they draw on top...but have the <circle> elements even lower in the document so that the circles draw on top of everything else.)
Can you make it so that when the user clicks and drags on the circles they stay under the mouse? (Hint: see this answer and example of mine, or go Google about making SVG elements draggable.)
During your drag handler, can you recalculate your triangle and points and lines and update them all? (Hint: you can either use setAttribute() to update attributes of SVG elements, e.g. setAttribute(myPoly,'points',arrayOfPoints.join()), or you can use SVG DOM bindings—e.g. myPoly.getItem(0).x = 43.)
Your question is too broad and vague currently. Either edit this question to make it specific to your exact desire and the exact code that is not working for you, or create a new question that is similarly targeted. Your code snippet does basically nothing useful for all the code you have in there.

Categories