Automatically add pixels when adding rectangle to canvas - javascript

For the moment, I have this
var x = 150;
var o = 100;
var canvas = $('#NodeList').get(0);
var ctx = canvas.getContext('2d');
ctx.strokeStyle = "red";
canvas.height = 0;
var rects = [
[20, 20, x, o],
[20, 130, x, o],
[20, 240, x, o],
[20, 350, x, o],
[20, 460, x, o],
[20, 570, x, o],
[20, 680, x, o],
[20, 790, x, o],
[20, 900, x, o]
];
as you can see i have added manually every rectangle.
I want to add automatically 70 pixels by each rectangle added by uses a jQuery function drawRect().
I have tried this so far Jcanvas
My reason for this is that i want to load data into an other canvas by clicking on the rectangle in this "canvas". I think it would be easier by using JQuery drawRect() instead of typing it manually like I did below. Since the rectangles dont have any ID.
I am stuck can you please clearify things for me?

You need something like this as I understood from your comment:
// Using Canvas API
ctx.fillStyle = '#000000';
rects.forEach(function (rect) {
ctx.fillRect.apply(ctx, rect);
});
// Using Jcanvas
var canvas = $('#NodeList');
rects.forEach(function (rect) {
canvas.drawRect({
fillStyle: '#000000',
x: rect[0],
y: rect[1],
width: rect[2],
height: rect[3]
});
});

Related

How to draw lines dynamically on SVG Picture?

I'm trying to develop an Attack Map when basically like all maps it will show the "Attacks" that are happening over the world but basically it will be randomly as I don't have access to any AV's APIs to get correct data. As of now I only have this SVG map shown on my HTML page:
And I'd want to draw some lines from one country to another to simulate the attacks. I have been searching about this and I have seen two "solutions". One is a JS code that draws a line in HTML:
if (stroke){
ctx.strokeStyle = stroke;
}
if (width){
ctx.lineWidth = width;
}
ctx.beginPath();
ctx.moveTo(...begin);
ctx.lineTo(...end);
ctx.stroke();
}
const canvas = document.querySelector("#line");
if(canvas.getContext){
const ctx = canvas.getContext('2d');
drawLine(ctx, [100, 100], [300, 100], 'green', 5)
}
but as I said this draws a line outside of the SVG map and inside of HTML. I also saw a line tag which can be placed inside of SVG tags but it is static. I want to be dynamic and simulate the attacks. Is there any way I can do this? Thank you for your time!
Even if the SVG element is static, you can add <line /> elements dynamically when the DOM has loaded:
const lines = [
{
from: { x: 0, y: 20 },
to: { x: 30, y: 60 }
},
{
from: { x: 0, y: 20 },
to: { x: 30, y: 60 }
}
];
function addLine (x1, y1, x2, y2) {
const line = document.createElementNS('http://www.w3.org/2000/svg','line');
line.setAttribute("x1", x1);
line.setAttribute("y1", y1);
line.setAttribute("x2", x2);
line.setAttribute("y2", y2);
line.setAttribute("stroke", "white");
document.getElementById("mySvg").appendChild(line);
}
addEventListener("DOMContentLoaded", function () {
for (const line of lines) {
addLine(line.from.x, line.from.y, line.to.x, line.to.y);
}
});

How to add a edge to my toolbar [mxGraph - js]

I`m trying to add an edge to a toolbar in mxGraph. Vertex following the examples i can do it perfectly. But edges i can't do it, someone can help me? I declare a link style, but it doesn't work.
var addVertex = function(icon, w, h, style)
{
var vertex = new mxCell(null, new mxGeometry(0, 0, w, h), style);
vertex.setVertex(true);
var img = addToolbarItem(graph, toolbar, vertex, icon);
img.enabled = true;
graph.getSelectionModel().addListener(mxEvent.CHANGE, function()
{
var tmp = graph.isSelectionEmpty();
mxUtils.setOpacity(img, (tmp) ? 100 : 20);
img.enabled = tmp;
});
};
addVertex('images/rectangle.gif', 100, 40, '');
addVertex('images/rounded.gif', 100, 40, 'shape=link');
addVertex('images/ellipse.gif', 40, 40, 'shape=ellipse');
addVertex('images/rhombus.gif', 40, 40, 'shape=rhombus');
addVertex('images/triangle.gif', 40, 40, 'shape=triangle');
addVertex('images/cylinder.gif', 40, 40, 'shape=cylinder');
addVertex('images/actor.gif', 30, 55, 'shape=umlActor');
I think you can edit XML file of the toolbar you want to add edge to it, just like adding new cell to the toolbar
Though Edge is a cell object, it cannot be placed in the toolbar for drag and drop. If your intention is to create connection between vertices, you can use the following in your code and check:
mxConnectionHandler.prototype.connectImage = new mxImage('images/connector.gif', 16, 16);
On mouseover for any vertex (source vertex), one connection icon (With Right Arrow) will appear. Just click and drag that icon to the another vertex (Target Vertex). This will create edge between two verties
var addVertex = function(mylabel, icon, w, h, style)
{
var vertex = new mxCell(mylabel, new mxGeometry(0, 0, w, h), style);
vertex.setVertex(true);
addToolbarItem(graph, toolbar, vertex, icon);
};
addVertex("None",'<c:url value="/resources/js/examples/editors/images/swimlane.gif"/>', 120, 160, 'shape=swimlane;startSize=20;');
addVertex("Catagory 1",'<c:url value="/resources/js/examples/editors/images/rectangle.gif"/>', 100, 40, 'shape=rectangle');
addVertex("Catagory 2",'<c:url value="/resources/js/examples/editors/images/rounded.gif"/>', 100, 40, 'shape=rounded');
addVertex("Catagory 3",'<c:url value="/resources/js/examples/editors/images/ellipse.gif"/>', 40, 40, 'shape=ellipse');
addVertex("Catagory 4",'<c:url value="/resources/js/examples/editors/images/rhombus.gif"/>', 40, 40, 'shape=rhombus');
addVertex("Catagory 5",'<c:url value="/resources/js/examples/editors/images/triangle.gif"/>', 40, 40, 'shape=triangle');
addVertex("Catagory 6",'<c:url value="/resources/js/examples/editors/images/cylinder.gif"/>', 40, 40, 'shape=cylinder');
addVertex("Catagory 7",'<c:url value="/resources/js/examples/editors/images/actor.gif"/>', 30, 40, 'shape=actor');
// toolbar.addLine();

How to add gravity to multiple bodies 'automatically'?

I know how to add gravity to any given object/element. Just add acceleration Y downwards. But "what if want my hero to fly?" or "what if I want to turn gravity off for one particular object? I'll have to set gravity = 0 which will turn off for everyone obviously. I also thought giving every shape their own 'gravity' variable, but I figured that would be too much and it's probably not how it's done...
How would I go from creating shapes
(Using EaseJS)
function spawnShape(x, y, w, h) {
var shape = new createjs.Shape();
shape.graphics.beginFill("black").drawRect(x, y, w, h);
stage.addChild(shape);
}
spawnShape(20, 250, 600, 30);
spawnShape(200, 150, 5, 5);
stage.update();
to adding gravity "automatically"? (every shape inheriting downwards acceleration) I know there's 2D physics engines made but I want to do/understand this myself, and I did try to use PhysicsJS but failed to do so.. I'll probably be using an engine but for now I want to know how to do this :P
You can create an object:
function Shape(x, y, w, h, gravity){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.gravity = gravity;
this.shape = new createjs.Shape();
stage.addChild(shape);
this.draw = function(){
shape.graphics.beginFill("black").drawRect(x, y, w, h);
}
}
Thus, you can call it as:
> x = new Shape(200, 200, 10, 10, 0.5)
Shape {x: 200, y: 200, w: 10, h: 10, gravity: 0.5}
> y = new Shape(400, 100, 50, 100, 0.75)
Shape {x: 400, y: 100, w: 50, h: 100, gravity: 0.75}
> x.gravity = 0
0
> y.gravity
0.75
I haven't worked with EaseJS so the specifics may be inaccurate but the overarching logic will be as demonstrated above.
I think you understand how to add gravity or not add gravity to an object. As you say, it is just adding acceleration Y to the object.
It sounds like you just need to think out your design a little. Let's say you have a module 'gravity.js' that is responsible for applying gravity to an object.
/* gravity.js */
const DEFAULT_GRAVITY_ACCELERATION = 1.0;
function applyGravity(shape) {
const gravity = shape.gravityAcceleration !== undefined ?
shape.gravityAcceleration : DEFAULT_GRAVITY_ACCELERATION;
//Do whatever you normally do to update Y acceleration. Code below
//is just an example.
shape.addYAcceleration(gravity);
}
If you create a shape someplace and want it to be free of gravity, just set the .gravityAcceleration member of that object. BTW, there is nothing special about that "gravityAcceleration" name--it could be whatever you want.
//Assuming spawnShape returns an object.
var superman = spawnShape(20, 250, 600, 30);
superman.gravityAcceleration = 0; //Override the default gravity.
You only need to set the .gravityAcceleration member for shape objects that will defy gravity.

putImageData of only portion of image data object

I have an ImageData object which holds the screenshot of all monitors, so it is one huge ImageData. I want to now draw one monitor per time. I have all the monitor dimensions.
So I'm trying to use ctx.putImageData(myImgDat, topLeftMonX, topLeftMonY, monWidth, monHeight) but its not working, I dont think I understand the dirty concept so well as seen in docs: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/putImageData#Understanding_putImageData
Is it possible to draw portion of imgaedata to canvas?
Yes, it's possible, it doesn't work on your code is because your arugments passed is not met the format of the function.
As MDN CanvasRenderingContext2D.putImageData() describes, it accepts 3 or 7 arguments, you have to pass either 3 or 7, otherwise, in your example, monWidth and monHeight will be used as dirtyX and dirtyY instead of dirtyWidth and dirtyHeighy. You code would probably do
Copy the rect(monWidth, monHeight, IMAGEDATA_WIDTH, IMAGEDATA_HEIGHT).
Put it on canvas's rect(topLeftMonX + monWidth, topLeftMonY + monHeight, IMAGEDATA_WIDTH, IMAGEDATA_HEIGHT).
So, and it's somehow not very straight to put the target region to (0,0) of the target canvas, to achieve by your give condition, you may have to do:
First move imageData's (0,0) to target canvas's (-topLeftMonX,
-topLeftMonY).
Then start to put imageData at imageData's (topLeftMonX, topLeftMonY) which now is at the position (0, 0) of canvas.
The rectangle size will be topLeftMonX x topLeftMonY.
ctx.putImageData(myImgDat,-topLeftMonX, -topLeftMonY, topLeftMonX, topLeftMonY, monWidth, monHeight);
Code above will copy the rect(topLeftMonX, topLeftMonY, monWidth, monHeight) on myImgDat to: rect(0, 0, monWidth, monHeight) on canvas.
You can take a look at how it works from the snippet below.
var canvas = document.getElementById('bigCanvas')
,ctx = canvas.getContext('2d');
var tcanvas = document.getElementById('testCanvas')
,tctx = tcanvas.getContext('2d');
var grd = tctx.createRadialGradient(150, 100, 10, 150, 110, 150);
grd.addColorStop(0, "black");
grd.addColorStop(0.15, "blue");
grd.addColorStop(0.3, "cyan");
grd.addColorStop(0.5, "green");
grd.addColorStop(0.7, "yellow");
grd.addColorStop(0.85, "orange");
grd.addColorStop(1, "red");
tctx.fillStyle = grd;
tctx.fillRect(0, 0, 300, 200);
var imageData = tctx.getImageData(0, 0, 300, 200);
// Move imagedata's origin to (-150, -100) on canvas,
// start to put data on canvas at imgae data's (150, 100) and size is 150x100
// => copy rect(150, 100, 150, 100) to canvas' s rect (0, 0, 150, 100)
ctx.putImageData(imageData, -150, -100, 150, 100, 150, 100);
// Move imagedata's origin to (150, 100) on canvas,
//start to put data on canvas at imgae data's (0, 0) and and size is 150x100
// => copy rect(0, 0, 150, 100) to canvas' s rect (150, 100, 150, 100)
ctx.putImageData(imageData, 150, 100, 0, 0, 150, 100);
// Move imagedata's origin to (150, -100) on canvas,
// start to put data on canvas at imgae data's (0, 100) and size is 150x100
// => copy rect(0, 100, 150, 100) to canvas' s rect (150, 0, 150, 100)
ctx.putImageData(imageData, 150, -100, 0, 100, 150, 100);
// Move imagedata's origin to (-150, 100) on canvas,
// start to put data on canvas at imgae data's (200, 0) and size is 100x100
// => copy rect(200, 0, 150, 100) to canvas' s rect (50, 100, 150, 100)
ctx.putImageData(imageData, -150, 100, 200, 0, 100, 100);
<div>Canvas for put ImageData:</div>
<canvas id="bigCanvas" width="300" height="200"></canvas>
<hr/>
<div>Canvas for get ImageData:</div>
<canvas id="testCanvas" width="300" height="200"></canvas>
This is another solution:
var iref = imagedata.data;
// start - because took a single screenshot of alllll put togather, lets portion out the imagedata
console.time('portion out image data');
for (var i=0; i<collMonInfos.length; i++) {
var screenUseW = collMonInfos[i].w;
var screenUseH = collMonInfos[i].h;
var screnImagedata = new ImageData(screenUseW, screenUseH);
var siref = screnImagedata.data;
var si = 0;
for (var y=collMonInfos[i].y; y<collMonInfos[i].y+screenUseH; y++) {
for (var x=collMonInfos[i].x; x<collMonInfos[i].x+screenUseW; x++) {
var pix1 = (fullWidth*y*4) + (x * 4);
var B = iref[pix1];
siref[si] = iref[pix1+2];
siref[si+1] = iref[pix1+1];
siref[si+2] = B;
siref[si+3] = 255;
si += 4;
}
}
collMonInfos[i].screenshot = screnImagedata;
}
console.timeEnd('portion out image data');

How to change the size of an animated circle onclick using raphael js

I've got a animated circle which looks like this:
the blue part counts down, so for example from full to nothing in 10 seconds. The orange circle is just a circle. But I want that the circle will be smaller when you click on it. So i made an onclick event for the circle.
circleDraw.node.onclick = function () {
circleDraw.animate({
stroke: "#E0B6B2",
arc: [100, 100, 100, 100, 100]
}, 500);
circleDraw.toFront();
};
That works, i've made it for both of the circles, they both become smaller but, After the 500 mili seconds the blue circle becomes big again because the timer for the blue circle got the parameters that it should be bigger.
circleDraw.animate({
arc: [100, 100, 0, 100, 500]
}, 10000);
Because the blue circle counts for 10 seconds it becomes automatically bigger again. How do I make both circles smaller but keep the timer counting down?
I was thinking of stopping the animation for the blue circle and save the remaining mili seconds of the animation draw it again smaller and start the animation again with the remaining seconds, but I don't know how to do this. But maybe i'm looking in the wrong direction and do I have to make it different.
Thanks.
All my code:
/************************************************************************/
/* Raphael JS magic
*************************************************************************/
var drawTheCircleVector = function(xloc, yloc, value, total, R) {
var alpha = 360 / total * value,
a = (90 - alpha) * Math.PI / 180,
x = xloc + R * Math.cos(a),
y = yloc - R * Math.sin(a),
path;
if (total == value) {
path = [
["M", xloc, yloc - R],
["A", R, R, 0, 1, 1, xloc - 0.01, yloc - R]
];
} else {
path = [
["M", xloc, yloc - R],
["A", R, R, 0, +(alpha > 180), 1, x, y]
];
}
return {
path: path
};
}; /************************************************************************/
/* Make the circles
*************************************************************************/
var timerCircle = Raphael("timer", 320, 320);
var circleBg = Raphael("backgroundCircle", 320, 320);
timerCircle.customAttributes.arc = drawTheCircleVector
circleBg.customAttributes.arc = drawTheCircleVector
/************************************************************************/
/* draw the circles
*************************************************************************/
var drawMe = circleBg.path().attr({
"fill": "#FF7F66",
"stroke": 0,
arc: [160, 160, 100, 100, 140]
});
var clickOnes = true;
drawMe.node.onclick = function() {
if (clickOnes == true) {
circleDraw.animate({
arc: [100, 100, 0, 100, 100]
}, 500);
circleDraw.toFront();
drawMe.animate({
arc: [100, 100, 100, 100, 100]
}, 500);
circleDraw.toFront();
clickOnes = false;
} else {
circleDraw.animate({
arc: [160, 160, 0, 100, 150]
}, 500);
circleDraw.toFront();
drawMe.animate({
arc: [160, 160, 100, 100, 140]
}, 500);
circleDraw.toFront();
clickOnes = true;
}
};
// arc: [Xposition, Yposition, how much 1 = begin 100 = end, ? = 100, 150];
/************************************************************************/
/* Draw the circle
*************************************************************************/
var circleDraw = timerCircle.path().attr({
"stroke": "#2185C5",
"stroke-width": 10,
arc: [160, 160, 100, 100, 150]
});
circleDraw.animate({
arc: [160, 160, 0, 100, 150]
}, 9000);
window.setInterval(function() {
goToNextStopGardensPointBus210()
}, 9000);
Here is my code the timer works and if you click on the circle it will become smaller but if you click on it before the bue cirlce is done it will become big again.
UPDATE
working version of what I got on jsFiddle,
http://jsfiddle.net/hgwd92/2S4Dm/
Here's a fiddle for you..
The issue was you where redrawing the items, with new animation speeds and such. Using the transform function, you can add a scaling transform that acts independent of the draws.
circleDraw.animate({transform: 'S0.5,0.5,160,160', 'stroke-width': 5}, 500);
and then to set it back...
circleDraw.animate({transform: 'S1,1,160,160', 'stroke-width': 10}, 500);
Note you need to set the center for the blue arc (the 160, 160), or once it gets past half way the center of the arc will move and it will scale to a different position.
EDIT: Updated the fiddle and code to scale the blue line to so it looks better.

Categories

Resources