418 lines
14 KiB
JavaScript
418 lines
14 KiB
JavaScript
|
|
// Function used to change the zoom level wrt to a point
|
|
// fn to change scale (zoom) - It also shifts origin so that the position
|
|
// of the object in focus doesn't change
|
|
function changeScale(delta,xx,yy,method=1) {
|
|
|
|
// method = 3/2 - Zoom wrt center of screen
|
|
// method = 1 - Zoom wrt position of mouse
|
|
// Otherwise zoom wrt to selected object
|
|
|
|
if(method==3){
|
|
xx =(width/2 - globalScope.ox) / globalScope.scale
|
|
yy = (height/2 - globalScope.oy) / globalScope.scale
|
|
}
|
|
else if(xx===undefined||yy===undefined||xx=='zoomButton'||yy=='zoomButton'){
|
|
if (simulationArea.lastSelected && simulationArea.lastSelected.objectType!="Wire") { // selected object
|
|
xx = simulationArea.lastSelected.x;
|
|
yy = simulationArea.lastSelected.y;
|
|
} else { //mouse location
|
|
if(method==1){
|
|
xx = simulationArea.mouseX;
|
|
yy = simulationArea.mouseY;
|
|
}
|
|
else if(method==2){
|
|
xx =(width/2 - globalScope.ox) / globalScope.scale
|
|
yy = (height/2 - globalScope.oy) / globalScope.scale
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
var oldScale = globalScope.scale;
|
|
globalScope.scale = Math.max(0.5,Math.min(4*DPR,globalScope.scale+delta));
|
|
globalScope.scale = Math.round(globalScope.scale * 10) / 10;
|
|
globalScope.ox -= Math.round(xx * (globalScope.scale - oldScale)); // Shift accordingly, so that we zoom wrt to the selected point
|
|
globalScope.oy -= Math.round(yy * (globalScope.scale - oldScale));
|
|
// dots(true,false);
|
|
|
|
|
|
// MiniMap
|
|
if(!embed && !lightMode){
|
|
findDimensions(globalScope);
|
|
miniMapArea.setup();
|
|
$('#miniMap').show();
|
|
lastMiniMapShown = new Date().getTime();
|
|
$('#miniMap').show();
|
|
setTimeout(removeMiniMap,2000);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//fn to draw Dots on screen
|
|
//the function is called only when the zoom level or size of screen changes.
|
|
// Otherwise for normal panning, the canvas itself is moved to give the illusion of movement
|
|
|
|
function dots(dots=true, transparentBackground=false,force=false) {
|
|
|
|
var scale = unit * globalScope.scale;
|
|
var ox = globalScope.ox % scale; //offset
|
|
var oy = globalScope.oy % scale; //offset
|
|
|
|
document.getElementById("backgroundArea").style.left=(ox-scale)/DPR;
|
|
document.getElementById("backgroundArea").style.top=(oy-scale)/DPR;
|
|
|
|
if(globalScope.scale==simulationArea.prevScale && !force)return;
|
|
|
|
if(!backgroundArea.context)return;
|
|
simulationArea.prevScale=globalScope.scale;
|
|
|
|
var canvasWidth = backgroundArea.canvas.width; //max X distance
|
|
var canvasHeight = backgroundArea.canvas.height; //max Y distance
|
|
|
|
var ctx = backgroundArea.context;
|
|
ctx.beginPath();
|
|
backgroundArea.clear();
|
|
ctx.strokeStyle="#eee";
|
|
ctx.lineWidth=1;
|
|
if (!transparentBackground) {
|
|
ctx.fillStyle = "white";
|
|
ctx.rect(0, 0, canvasWidth, canvasHeight);
|
|
ctx.fill();
|
|
}
|
|
|
|
|
|
var correction=0.5*(ctx.lineWidth%2);
|
|
for (var i = 0 ; i < canvasWidth; i += scale){
|
|
ctx.moveTo(Math.round(i+correction)-correction,0);
|
|
ctx.lineTo(Math.round(i+correction)-correction,canvasHeight);
|
|
}
|
|
for (var j = 0 ; j < canvasHeight; j += scale){
|
|
ctx.moveTo(0,Math.round(j+correction)-correction);
|
|
ctx.lineTo(canvasWidth,Math.round(j+correction)-correction);
|
|
}
|
|
ctx.stroke();
|
|
|
|
|
|
return ;
|
|
|
|
// Old Code
|
|
// function drawPixel(x, y, r, g, b, a) {
|
|
// var index = (x + y * canvasWidth) * 4;
|
|
// canvasData.data[index + 0] = r;
|
|
// canvasData.data[index + 1] = g;
|
|
// canvasData.data[index + 2] = b;
|
|
// canvasData.data[index + 3] = a;
|
|
// }
|
|
// if (dots) {
|
|
// var canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
|
|
//
|
|
//
|
|
//
|
|
// for (var i = 0 + ox; i < canvasWidth; i += scale)
|
|
// for (var j = 0 + oy; j < canvasHeight; j += scale)
|
|
// drawPixel(i, j, 0, 0, 0, 255);
|
|
// ctx.putImageData(canvasData, 0, 0);
|
|
// }
|
|
}
|
|
|
|
// Helper canvas API starts here
|
|
// All canvas functions are wrt to a center point (xx,yy),
|
|
// direction is used to abstract rotation of everything by a certain angle
|
|
// Possible values for direction = "RIGHT" (default), "LEFT", "UP", "DOWN"
|
|
|
|
function bezierCurveTo(x1, y1, x2, y2, x3, y3, xx, yy, dir) {
|
|
[x1, y1] = rotate(x1, y1, dir);
|
|
[x2, y2] = rotate(x2, y2, dir);
|
|
[x3, y3] = rotate(x3, y3, dir);
|
|
var ox = globalScope.ox;
|
|
var oy = globalScope.oy;
|
|
x1 *= globalScope.scale;
|
|
y1 *= globalScope.scale;
|
|
x2 *= globalScope.scale;
|
|
y2 *= globalScope.scale;
|
|
x3 *= globalScope.scale;
|
|
y3 *= globalScope.scale;
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
ctx.bezierCurveTo(Math.round(xx + ox + x1), Math.round(yy + oy + y1), Math.round(xx + ox + x2), Math.round(yy + oy + y2), Math.round(xx + ox + x3), Math.round(yy + oy + y3));
|
|
}
|
|
|
|
function moveTo(ctx, x1, y1, xx, yy, dir,bypass=false) {
|
|
var correction=0.5*(ctx.lineWidth%2);
|
|
[newX, newY] = rotate(x1, y1, dir);
|
|
newX = newX * globalScope.scale;
|
|
newY = newY * globalScope.scale;
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
if(bypass)
|
|
ctx.moveTo(xx + globalScope.ox + newX,yy + globalScope.oy + newY);
|
|
else
|
|
ctx.moveTo(Math.round(xx + globalScope.ox + newX-correction)+correction, Math.round(yy + globalScope.oy + newY-correction)+correction);
|
|
}
|
|
|
|
function lineTo(ctx, x1, y1, xx, yy, dir) {
|
|
|
|
var correction=0.5*(ctx.lineWidth%2);
|
|
[newX, newY] = rotate(x1, y1, dir);
|
|
newX = newX * globalScope.scale;
|
|
newY = newY * globalScope.scale;
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
ctx.lineTo(Math.round(xx + globalScope.ox + newX-correction)+correction, Math.round(yy + globalScope.oy + newY-correction)+correction);
|
|
}
|
|
|
|
function arc(ctx, sx, sy, radius, start, stop, xx, yy, dir) {
|
|
|
|
//ox-x of origin, xx- x of element , sx - shift in x from element
|
|
|
|
var correction=0.5*(ctx.lineWidth%2);
|
|
[Sx, Sy] = rotate(sx, sy, dir);
|
|
Sx = Sx * globalScope.scale;
|
|
Sy = Sy * globalScope.scale;
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
radius *= globalScope.scale;
|
|
[newStart, newStop, counterClock] = rotateAngle(start, stop, dir);
|
|
ctx.arc(Math.round(xx + globalScope.ox + Sx+correction)-correction, Math.round(yy + globalScope.oy + Sy+correction)-correction, Math.round(radius), newStart, newStop, counterClock);
|
|
}
|
|
|
|
function arc2(ctx, sx, sy, radius, start, stop, xx, yy, dir) {
|
|
|
|
//ox-x of origin, xx- x of element , sx - shift in x from element
|
|
|
|
var correction=0.5*(ctx.lineWidth%2);
|
|
[Sx, Sy] = rotate(sx, sy, dir);
|
|
Sx = Sx * globalScope.scale;
|
|
Sy = Sy * globalScope.scale;
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
radius *= globalScope.scale;
|
|
[newStart, newStop, counterClock] = rotateAngle(start, stop, dir);
|
|
var pi = 0;
|
|
if(counterClock)
|
|
pi = Math.PI;
|
|
ctx.arc(Math.round(xx + globalScope.ox + Sx +correction)-correction, Math.round(yy + globalScope.oy + Sy + correction)-correction, Math.round(radius), newStart + pi, newStop + pi);
|
|
}
|
|
|
|
function drawCircle2(ctx, sx, sy, radius, xx, yy, dir) { //ox-x of origin, xx- x of element , sx - shift in x from element
|
|
|
|
[Sx, Sy] = rotate(sx, sy, dir);
|
|
Sx = Sx * globalScope.scale;
|
|
Sy = Sy * globalScope.scale;
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
radius *= globalScope.scale;
|
|
ctx.arc(Math.round(xx + globalScope.ox + Sx), Math.round(yy + globalScope.oy + Sy), Math.round(radius), 0, 2*Math.PI);
|
|
}
|
|
|
|
function rect(ctx, x1, y1, x2, y2) {
|
|
var correction=0.5*(ctx.lineWidth%2)
|
|
x1 = x1 * globalScope.scale;
|
|
y1 = y1 * globalScope.scale;
|
|
x2 = x2 * globalScope.scale;
|
|
y2 = y2 * globalScope.scale;
|
|
ctx.rect(Math.round(globalScope.ox + x1-correction)+correction, Math.round(globalScope.oy + y1-correction)+correction, Math.round(x2),Math.round( y2));
|
|
}
|
|
|
|
function rect2(ctx, x1, y1, x2, y2, xx, yy, dir="RIGHT") {
|
|
var correction = 0.5*(ctx.lineWidth%2);
|
|
[x1, y1] = rotate(x1, y1, dir);
|
|
[x2, y2] = rotate(x2, y2, dir);
|
|
x1 = x1 * globalScope.scale;
|
|
y1 = y1 * globalScope.scale;
|
|
x2 = x2 * globalScope.scale;
|
|
y2 = y2 * globalScope.scale;
|
|
xx *= globalScope.scale;
|
|
yy *= globalScope.scale;
|
|
ctx.rect(Math.round(globalScope.ox + xx + x1-correction)+correction, Math.round(globalScope.oy + yy + y1-correction)+correction, Math.round(x2), Math.round(y2));
|
|
}
|
|
|
|
|
|
function rotate(x1, y1, dir) {
|
|
if (dir == "LEFT")
|
|
return [-x1, y1];
|
|
else if (dir == "DOWN")
|
|
return [y1, x1];
|
|
else if (dir == "UP")
|
|
return [y1, -x1];
|
|
else
|
|
return [x1, y1];
|
|
}
|
|
|
|
function correctWidth(w){
|
|
return Math.max(1,Math.round(w*globalScope.scale));
|
|
}
|
|
|
|
function rotateAngle(start, stop, dir) {
|
|
if (dir == "LEFT")
|
|
return [start, stop, true];
|
|
else if (dir == "DOWN")
|
|
return [start - Math.PI / 2, stop - Math.PI / 2, true];
|
|
else if (dir == "UP")
|
|
return [start - Math.PI / 2, stop - Math.PI / 2, false];
|
|
else
|
|
return [start, stop, false];
|
|
}
|
|
|
|
function drawLine(ctx, x1, y1, x2, y2, color, width) {
|
|
x1 *= globalScope.scale;
|
|
y1 *= globalScope.scale;
|
|
x2 *= globalScope.scale;
|
|
y2 *= globalScope.scale;
|
|
ctx.beginPath();
|
|
ctx.strokeStyle = color;
|
|
ctx.lineCap = "round";
|
|
ctx.lineWidth = correctWidth(width);//*globalScope.scale;
|
|
var correction = 0.5*(ctx.lineWidth%2);
|
|
var hCorrection=0;
|
|
var vCorrection=0;
|
|
if(y1==y2)vCorrection=correction;
|
|
if(x1==x2)hCorrection=correction;
|
|
ctx.moveTo(Math.round(x1 + globalScope.ox+hCorrection)-hCorrection, Math.round(y1 + globalScope.oy+vCorrection)-vCorrection);
|
|
ctx.lineTo(Math.round(x2 + globalScope.ox+hCorrection)-hCorrection,Math.round(y2 + globalScope.oy+vCorrection)-vCorrection);
|
|
ctx.stroke();
|
|
}
|
|
|
|
// Checks if string color is a valid color using a hack
|
|
function validColor(color){
|
|
var $div = $("<div>");
|
|
$div.css("border", "1px solid "+color);
|
|
return ($div.css("border-color")!="")
|
|
}
|
|
|
|
// Helper function to color "RED" to RGBA
|
|
function colorToRGBA(color) {
|
|
var cvs, ctx;
|
|
cvs = document.createElement('canvas');
|
|
cvs.height = 1;
|
|
cvs.width = 1;
|
|
ctx = cvs.getContext('2d');
|
|
ctx.fillStyle = color;
|
|
ctx.fillRect(0, 0, 1, 1);
|
|
return ctx.getImageData(0, 0, 1, 1).data;
|
|
}
|
|
|
|
function drawCircle(ctx, x1, y1, r, color) {
|
|
|
|
x1 = x1 * globalScope.scale;
|
|
y1 = y1 * globalScope.scale;
|
|
ctx.beginPath();
|
|
ctx.fillStyle = color;
|
|
ctx.arc(Math.round(x1 + globalScope.ox), Math.round(y1 + globalScope.oy), Math.round(r*globalScope.scale), 0, Math.PI * 2, false);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
}
|
|
|
|
// To show message like values, node name etc
|
|
function canvasMessage(ctx,str,x1,y1,fontSize=10){
|
|
if(!str||!str.length)return;
|
|
|
|
ctx.font = Math.round(fontSize * globalScope.scale) + "px Georgia";
|
|
ctx.textAlign = "center"
|
|
var width=ctx.measureText(str).width/globalScope.scale+8;
|
|
var height=13;
|
|
ctx.strokeStyle="black";
|
|
ctx.lineWidth=correctWidth(1);
|
|
ctx.fillStyle="yellow";
|
|
ctx.save();
|
|
ctx.beginPath();
|
|
rect(ctx,x1 -width/2 , y1 -height/2-3, width, height);
|
|
ctx.shadowColor = '#999';
|
|
ctx.shadowBlur = 10;
|
|
ctx.shadowOffsetX = 3;
|
|
ctx.shadowOffsetY = 3;
|
|
ctx.stroke();
|
|
ctx.fill();
|
|
ctx.restore();
|
|
x1 = x1 * globalScope.scale;
|
|
y1 = y1 * globalScope.scale;
|
|
ctx.beginPath();
|
|
ctx.fillStyle="black";
|
|
ctx.fillText(str, Math.round(x1 + globalScope.ox), Math.round( y1 + globalScope.oy));
|
|
ctx.fill();
|
|
}
|
|
|
|
function fillText(ctx, str, x1, y1, fontSize = 20) {
|
|
x1 = x1 * globalScope.scale;
|
|
y1 = y1 * globalScope.scale;
|
|
ctx.font = Math.round(fontSize * globalScope.scale) + "px Georgia";
|
|
ctx.fillText(str, Math.round(x1 + globalScope.ox), Math.round( y1 + globalScope.oy));
|
|
}
|
|
|
|
function fillText2(ctx, str, x1, y1, xx, yy, dir) {
|
|
|
|
angle = {
|
|
"RIGHT": 0,
|
|
"LEFT": 0,
|
|
"DOWN": Math.PI / 2,
|
|
"UP": -Math.PI / 2,
|
|
}
|
|
x1 = x1 * globalScope.scale;
|
|
y1 = y1 * globalScope.scale;
|
|
[x1, y1] = rotate(x1, y1, dir);
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
|
|
ctx.font = Math.round(14 * globalScope.scale) + "px Georgia";
|
|
ctx.save();
|
|
ctx.translate( Math.round(xx + x1 + globalScope.ox), Math.round( yy + y1 + globalScope.oy));
|
|
ctx.rotate(angle[dir]);
|
|
ctx.textAlign = "center";
|
|
ctx.fillText(str, 0, Math.round(4 * globalScope.scale)*(1-0*(+(dir=="DOWN"))));
|
|
ctx.restore();
|
|
|
|
}
|
|
|
|
function fillText4(ctx, str, x1, y1, xx, yy, dir,fontSize=14,textAlign="center") {
|
|
angle = {
|
|
"RIGHT": 0,
|
|
"LEFT": 0,
|
|
"DOWN": Math.PI / 2,
|
|
"UP": -Math.PI / 2,
|
|
}
|
|
x1 = x1 * globalScope.scale;
|
|
y1 = y1 * globalScope.scale;
|
|
[x1, y1] = rotate(x1, y1, dir);
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
|
|
ctx.font = Math.round(fontSize * globalScope.scale) + "px Georgia";
|
|
// ctx.font = 20+"px Georgia";
|
|
ctx.textAlign = textAlign;
|
|
ctx.fillText(str,xx+x1+globalScope.ox,yy+y1+globalScope.oy+ Math.round(fontSize/3 * globalScope.scale));
|
|
|
|
|
|
}
|
|
|
|
function fillText3(ctx, str, x1, y1, xx = 0, yy = 0, fontSize = 14, font = "Georgia", textAlign = "center") {
|
|
|
|
x1 = x1 * globalScope.scale;
|
|
y1 = y1 * globalScope.scale;
|
|
xx = xx * globalScope.scale;
|
|
yy = yy * globalScope.scale;
|
|
|
|
ctx.font = Math.round(fontSize * globalScope.scale) + "px " + font;
|
|
ctx.textAlign = textAlign;
|
|
ctx.fillText(str, Math.round( xx + x1 + globalScope.ox), Math.round( yy + y1 + globalScope.oy));
|
|
|
|
}
|
|
|
|
|
|
oppositeDirection = {
|
|
"RIGHT": "LEFT",
|
|
"LEFT": "RIGHT",
|
|
"DOWN": "UP",
|
|
"UP": "DOWN",
|
|
}
|
|
fixDirection = {
|
|
"right": "LEFT",
|
|
"left": "RIGHT",
|
|
"down": "UP",
|
|
"up": "DOWN",
|
|
"LEFT": "LEFT",
|
|
"RIGHT": "RIGHT",
|
|
"UP": "UP",
|
|
"DOWN": "DOWN",
|
|
}
|