I'd been trying to write a small library in Javascript mainly for Canvas drawImage() method.
The main purpose of the library is to pass array values instead of passing single values such as :
// srcPos=[0,0] , size=[90,90], dstPos=[50,50]
function draw_image(context, image, srcPos, size, dstPos, size) {
context.drawImage(image, srcPos[0], srcPos[1], size[0], size[1], dstPos[0], dstPos[1], size[0], size[1]);
}
but when i called this function jzz like this, I'm getting Uncaught ReferenceError :
var canvas = document.getElementById("display"),
frame = canvas.getContext("2d");
var shipInfo = { center:[45, 45], size:[90, 90], radius: 35, angle:45 },
shipImage = new Image(),
pos = [40, 70];
shipImage.src = "ship.png";
function draw() {
draw_image(frame, shipImage, shipInfo.size, pos, shipInfo.size);
}
window.onload = function() {
draw();
}
And Is it possible to implement a method overriding the default drawImage() like this:
frame.draw_image(shipImage, srcPos, shipInfo.size, dstPos, shipInfo.size);
If you want to add a function to the 2d context, javascript makes this easy thanks to the prototype inheritance : You can inject the Context2D object to add or change its function as you wish.
You might want to look at a few addings i made to the context in a small canvas lib i made here : https://github.com/gamealchemist/CanvasLib
Some will tell that injecting is evil, but unless you're on a huge boat i would just say : If you use some graphic library, respect the semantic of existing functions and everything should be fine. If you don't use libs : do whatever it takes !
So, to answer more specifically to your question, your shorter drawImage would give :
CanvasRenderingContext2D.prototype.draw_image = function ( image,
srcPos, size,
dstPos, size) {
this.drawImage(image, srcPos[0], srcPos[1], size[0], size[1],
dstPos[0], dstPos[1], size[0], size[1]);
};
Then you can use the new function on all your contexts :
var canvas = document.getElementById("display"),
frame = canvas.getContext("2d");
frame.draw_image( ... ) ;
Notice that you could use 'rect' objects, which would be arrays with 4 elements, x, y, w, h, and lead to an even shorter syntax.
Edit : i see in your lib that you want to rotate your rect.
First thing is that you don't want to reset the transform. Just save it then restore it.
I would try something closer to this :
var x = dstPos[0],
y = dstPos[1],
halfWidth = dstSize[0]*0.5, // !! not src use >>1 if you know it's an int.
halfHeight = dstSize[1]*0.5, // !! not src ...
angleInRads = angle * Math.PI / 180;
this.save();
this.translate(x+halfWidth,y+halfHeight);
this.rotate(angleInRads);
this.drawImage(image
, center[0], center[1], srcSize[0], srcSize[1]
, -halfWidth, -halfHeight, dstSize[0],dstSize[1]);
this.restore();
Your small image library would fit well inside a javascript object.
A Demo: http://jsfiddle.net/m1erickson/7pZJw/
A javascript object can hold information about your image:
the image itself
the image size (can be automatically calculated for you)
the image centerpoint (can be automatically calculated for you)
Example:
// create a new object
// fill it with the info about the image
var object={
image:shipImage,
width:shipImage.width,
height:shipImage.height,
centerOffsetX:shipImage.width/2,
centerOffsetY:shipImage.height/2,
radius:35,
angle:45,
};
A javascript object can also hold functions that draws the image (as you've done in your code)
Example:
// when you call object.draw the image will be drawn by this function
// which is added to the object itself
draw:function(context,atX,atY,newWidth,newHeight){
context.drawImage(
this.image,
0,0,this.width,this.height,
atX,atY,newWidth,newHeight);
},
A function to create your small image library inside a javascript object might look like this:
function createImageObject(image,radius,angle){
// create a new object
// fill it with the info about the image
var object={
image:image,
width:image.width,
height:image.height,
centerOffsetX:image.width/2,
centerOffsetY:image.height/2,
radius:radius,
angle:angle,
draw:function(context,atX,atY,newWidth,newHeight){
context.drawImage(
this.image,
0,0,this.width,this.height,
atX,atY,newWidth,newHeight);
},
};
return(object);
}
And you can use your ship object library like this:
// create a new ship object
var shipObject=createImageObject(img,35,45);
// draw the ship image using the ship object
// draw at 20,20 with size 75,75
shipObject.draw(frame,20,20,75,75);
BTW, I see you're using the version of drawImage that will scale/clip the source image.
If you just want to draw the full image at its original size you can do this shortcut:
// draw the image full-sized at x,y
context.drawImage(image,x,y);
Related
I actually work on AR project with three.js and i handle some 3d models, but I have some problem with the sizes of the models. Because I want them to all have the same size, so I needed to set the same dimensions to all models. I first tried to solve this by using boundingbox and boundingsphere but it doesn't work.
So how can I get the sizes and how can I set the sizes ?
var size = new THREE.Box3().setFromObject( yourObject ).getSize(new THREE.Vector3())
I need somethig else, because the code of manthrax is interesting but have some limits.. for exemple with this code:
andy.scale.set(0.011, 0.011, 0.011);
andy.rotation.set(0, 0, 0);
andy.position.set(0,0,0);
var size = new THREE.Box3().setFromObject(andy).getSize(new THREE.Vector3())
console.log(size);
function moy(vect){
return ((vect.x+vect.y+vect.z)/3);;
}
console.log(moy(size));
andy.scale.set(0.030, 0.030, 0.030);
console.log(moy(size));
If i want to change the value of "size" how can i do that ?
PS: andy is my 3d model
I solve it, i create my own box3:
andy.scale.set(0.011, 0.011, 0.011);
andy.rotation.set(0, 0, 0);
andy.position.set(0,0,0);
var box3d = new THREE.Box3();
var size = box3d.setFromObject(andy).getSize(new THREE.Vector3())
console.log(size);
function moy(vect){
return ((vect.x+vect.y+vect.z)/3);;
}
console.log(moy(size));
andy.scale.set(0.030, 0.030, 0.030);
box3d.setFromObject(andy).getSize(size);
console.log(moy(size));
is it possible to pass a value from openjscad to javascript?
I would like to show the dimensions of a 3d-object in a div or any other html-element.
Example:
A cube is created with openjscad with the following parameters:
function main() {
var cube = CSG.cube({
center: [0, 0, 0],
radius: [1, 2, 3]
});
return cube;
}
How can I pass the parameters for center and radius to javascript in order to use them in other areas of the website?
I did this by making my own cube object, you can add all the variables you want and add some functions too like my translate function.
function myCube(size,pos){
this.obj = cube({size:size,center:false}).translate(pos);
this.size = size;
this.pos = pos;
this.translate = function(pos){
this.obj.translate(pos);
};
}
then you can make a cube like this var MC = new myCube(radius, [x,y,z]);
and now to get your radius you can do MC.size;
it does get tricky when you try to do something with the shape itself, you'll have to do something like union(MC.obj, CIL.obj)
ps: I hope this helps although I know this isn't the ideal way and there's probably some easy way of doing it but this worked for me.
I am building a real-time canvas clicking game, and am almost complete.
I need to change the colour of a canvas drawn element. I hear this cannot be done.
I have a variable holding these properties of the clicked shape for use on both clients:
{ x: 446.48232363630086,
y: 279.37327971844934,
dx: 2.829614687943831,
dy: -3.0215198849327862,
rad: 26,
color: 'rgb(146,25,122)' }
And I have another variable holding a new colour, if it is not possible to change the colour of a something drawn on the canvas, can I edit the object in the array which would make my current drawShape function redraw the changed shape? This is my old single player code for some reference.
https://jsfiddle.net/a9b3rm5u/5/ Thank you
I figured it out:
var i = data.shapeRemoval;//object data
var c = data.colours; // colour data
var r = c;
shapes.splice(i,1); // removes old object from array
i.color = c; // replaces the color in the object for the variable C
shapes.push(i)// pushes to array
I've built a name-[rgb] Javascript object. Your basic:
namedColors = {
AliceBlue: [240, 248, 255],
AntiqueWhite: [250, 235, 215],
...
object. But it occurred to me that I should be able to take a name string, "AliceBlue", say .. and have JavaScript find some sort of RGB representation of it (hex is fine). I know there are at least 140 named colors tucked away in the browser, but I can't seem to find them.
Is there a CSS or "style=..." stunt that lets me look up an RGB representation of a color name?
Minimal JavaScript function:
function nameToRgba(name) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.fillStyle = name;
context.fillRect(0,0,1,1);
return context.getImageData(0,0,1,1).data;
}
This is the solution I ended up with. I realized that colors came in two types: css strings and webgl typed arrays (usually 4 floats or ints, depending).
Hell with it, let the browser figure it: create a 1x1 canvas, fill it with any string color, grab the pixel, and destructure into an rgba array. There are two utilities below that create the 1x1 2d canvas ctx, attached.
# Return an RGB array given any legal CSS color, null otherwise.
# http://www.w3schools.com/cssref/css_colors_legal.asp
# The string can be CadetBlue, #0f0, rgb(255,0,0), hsl(120,100%,50%)
# The rgba/hsla forms ok too, but we don't return the a.
# Note: The browser speaks for itself: we simply set a 1x1 canvas fillStyle
# to the string and create a pixel, returning the r,g,b values.
# Warning: r=g=b=0 can indicate an illegal string. We test
# for a few obvious cases but beware of unexpected [0,0,0] results.
ctx1x1: u.createCtx 1, 1 # share across calls. closure wrapper better?
stringToRGB: (string) ->
#ctx1x1.fillStyle = string
#ctx1x1.fillRect 0, 0, 1, 1
[r, g, b, a] = #ctx1x1.getImageData(0, 0, 1, 1).data
return [r, g, b] if (r+g+b isnt 0) or
(string.match(/^black$/i)) or
(string in ["#000","#000000"]) or
(string.match(/rgba{0,1}\(0,0,0/i)) or
(string.match(/hsla{0,1}\(0,0%,0%/i))
null
What I love about it is that The Browser Speaks For Itself. Any legal string works just fine. Only downside is that if the string is illegal you get black, so need to do a few checks. The error checking is not great, but I don't need it in my usage.
The utility functions:
# Create a new canvas of given width/height
createCanvas: (width, height) ->
can = document.createElement 'canvas'
can.width = width; can.height = height
can
# As above, but returing the context object.
# Note ctx.canvas is the canvas for the ctx, and can be use as an image.
createCtx: (width, height) ->
can = #createCanvas width, height
can.getContext "2d"
Have a look into Colors.js with the functions "name2hex" and "name2rgb" this libary returns the hex or rgb values of your color name.
You can use a canvas to get the RGBA color from a name.
Please look at this fiddle: https://jsfiddle.net/AaronWatters/p1y298zk/19/
// We want to know the rgba values for this color name:
var testColor = "salmon"
// make a canvas
var canvas = $('<canvas width="100px" height="100px">');
// optional: display the canvas
var body = $(document.body);
canvas.appendTo(body);
// draw a rectangle on the canvas
var context = canvas[0].getContext("2d");
context.beginPath();
context.rect(0,0,100,100);
context.fillStyle = testColor;
context.fill();
// get the canvas image as an array
var imgData = context.getImageData(0, 0, 10, 10);
// rbga values for the element in the middle
var array = imgData.data.slice(50*4, 50*4+4);
// convert the opacity to 0..1
array[3] = array[3] / 255.0;
$("<div>The rgba for " + testColor + " is " + array + "</div>").appendTo(body);
This is how jp_doodle does color interpolation in transitions: https://aaronwatters.github.io/jp_doodle/080_transitions.html
Other approaches on this page use HTML5 Canvas.
But a straightforward alternative would be to derive the rgb() value from any color keyword using:
window.getComputedStyle()
Working Example:
const colorKeywordToRGB = (colorKeyword) => {
// CREATE TEMPORARY ELEMENT
let el = document.createElement('div');
// APPLY COLOR TO TEMPORARY ELEMENT
el.style.color = colorKeyword;
// APPEND TEMPORARY ELEMENT
document.body.appendChild(el);
// RESOLVE COLOR AS RGB() VALUE
let rgbValue = window.getComputedStyle(el).color;
// REMOVE TEMPORARY ELEMENT
document.body.removeChild(el);
return rgbValue;
}
// BASIC COLORS
console.log('red:', colorKeywordToRGB('red'));
console.log('green:', colorKeywordToRGB('green'));
console.log('yellow:', colorKeywordToRGB('yellow'));
console.log('blue:', colorKeywordToRGB('blue'));
// SIMPLE COLORS
console.log('fuchsia:', colorKeywordToRGB('fuchsia'));
console.log('lime:', colorKeywordToRGB('lime'));
console.log('maroon:', colorKeywordToRGB('maroon'));
console.log('navy:', colorKeywordToRGB('navy'));
console.log('olive:', colorKeywordToRGB('olive'));
console.log('purple:', colorKeywordToRGB('purple'));
console.log('teal:', colorKeywordToRGB('teal'));
console.log('transparent:', colorKeywordToRGB('transparent'));
// ADVANCED COLORS
console.log('blanchedalmond:', colorKeywordToRGB('blanchedalmond'));
console.log('coral:', colorKeywordToRGB('coral'));
console.log('darkorchid:', colorKeywordToRGB('darkorchid'));
console.log('firebrick:', colorKeywordToRGB('firebrick'));
console.log('gainsboro:', colorKeywordToRGB('gainsboro'));
console.log('honeydew:', colorKeywordToRGB('honeydew'));
console.log('papayawhip:', colorKeywordToRGB('papayawhip'));
console.log('seashell:', colorKeywordToRGB('seashell'));
console.log('thistle:', colorKeywordToRGB('thistle'));
console.log('wheat:', colorKeywordToRGB('wheat'));
Further Reading:
https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
I am Currently Trying to work with JavaScript in a cleaner object orientated way, So Please excuse me if I'm doing this entirely incorrectly I am using this previous questions answer as a general reference, but Here's my 'test' code:
//Create some sample objects to play with.
var testJSON = {
"rectangle": [
{ "id":3 , "x":5, "y":10, "width":10, "height":50
}
]
};
//Create Rectangle Constructor
var rectangle = {
init: function( i, x, y, width, height ) {
this.id = i,
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.fields = []
},
move: function( x, y ) {
this.x += x;
this.y += y;
}
};
//Create test array to hold all the objects
var test = [];
//Create a new rectangle object
var myRectangle = Object.create( rectangle );
myRectangle.init( 1, 0, 0, 2, 4 );
myRectangle.move( 3, 5 );
//put rectangle object in array associated with id
test[myRectangle.id] = myRectangle;
//Create a new rectangle object with the same variable name as it will all be in an array anyway.
var myRectangle = Object.create( rectangle );
myRectangle.init( 2, 0, 0, 2, 4 );
myRectangle.move( 0, 0 );
//put rectangle object in array associated with id
test[myRectangle.id] = myRectangle;
//put JSON result in
test[testJSON.rectangle[0].id] = testJSON.rectangle[0];
//No Longer need this variable, is it worth getting rid of.. i dont know
myRectangle =null;
//Try and use methods created in the constructor.
test[2].move(4,8);
console.log(test);
Okay, Now the actual questions, The Application I am trying to create, has both json data and it will have users that create data, so for example: the application will generate a bunch of 'rectangles' and then the user can also create rectangles.
So the first question would be, 'Is this the correct approach' and then secondly how would i get the json data to also have the method defined in the rectangle constructor (move)?
Any Help Greatly Appreciated.
This an extension of what #Marc B and #Ray Toal mentioned...
You have created javascript functions - which is not at all that bad - but not JSON. To create graphics, you could use the canvas tag as, in effect, a "drawing div" and use the object's x and y positions to constantly update them - if you were considering doing 2d animation. If so, I would recommend CreateJs as a starting block before hard-coding JAVASCRIPT animations. Again, you're code is just fine, but having users create this data - if you were considering a server application would involve using real JSON or perhaps Node.js - but for now I'd focus on single player aspect and setting up you're objects on a graphical 'interface' like <canvas>