I continue my experiments with HTML5 Canvas and JavaScript. I continue making a simple interactive game for my kids. Here is jsfiddle for my template: jsfiddle.net/LmCwZ/
The question is how I can work with each tab and populate it with a content it separately? Because in some of them I want to insert images and text. Thank you in advance.
You can simply extend the object with more properties to hold your content such as text, images or draw commands etc.
For example, to add text capability:
var Tab = function(id, x, y, width, height, text, color) {
...snipped
this.content = null;
...snipped
and then after creating the tab (or extend its constructor) you define the text:
myTab.content = 'Text for this tab!';
Now in the update method you can render the text of the current tab if there is any:
function showContent(tab) {
ctx.fillStyle = tab.color;
ctx.fillRect(0, tab.height, ctx.canvas.width, 700);
// has text?
if (tab.content !== null) {
ctx.fillStyle = tab.textColor;
ctx.textAlign = 'left';
ctx.font = '40px sans-serif';
ctx.fillText(tab.content, 30, 160);
}
}
Updated fiddle here
The text color, position could just as easily be part of the properties of the object (tab.textX, tab.textY etc.).
With this approach you do not need to worry about indexes (which is a nice alternative though) as everything is self-contained in the object.
Do the same for image but be aware that image loading is asynchronous so it is an advantage to store the image object itself on the tab object rather than an url (or use the constructor phase to pre-load the image).
Also, you will have to manually format text as this is canvas (or use SVG in combination with canvas for more complex stuff as I show in this article). This includes text wrapping, lines etc.
If you need advanced formatting in each tab I would recommend standard HTML and CSS instead of using canvas.
Related
I'm two days into js,html and css programming. So very newbie!
Following and building upon this TUTORIAL
Q1: How can I add this male into the background (see figuere 1.) and prohibit any strokes outside of the borders?
Adding image to background was no biggy!
function make_base()
{
base_image = new Image();
base_image.src = 'img/bmapFront.gif';
base_image.onload = function(){
context.drawImage(base_image, 0,0);
}
}
There is a context.clip function, not sure if I can use pixel form as clipping path. Making tons of "image substractions" isn't the best way.
Any suggestions
Edit:
Did the Job for me: VeryHelpful
var frontPath = new Path2D ("M 133.41,17.00 C 141.37,2.41 160.66, !VERY LONG! ")
context.clip(frontPath);
Messy strokes!
He should look like this. Then I want to save him.
Although there is such a thing as ctx.clip(), this is sometimes not what's wanted as it's impractical to use a path.
The solution that I like involves creating a virtual empty canvas onto which you draw your pixel image. Through various manipulations, like using ctx.getImageData and similar to make sure you only get one kind of color or apply other filters only once, you can obtain an image that seems to be empty (alpha of 0, mostly) in the places where you want to clip other images or paths out.
At that point, you'd use ctx.globalCompositeOperation = 'source-atop', or pick another one you might want to use from mdn's list of globalCompositeOperations.
At this point, you can just draw this virtual canvas image onto the main canvas
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I Want to have an image of a car, and when a user clicks a spot on the car, I drop an x image or a circle image on that spot. I need to save the spot where they clicked so when they come back I display it in the same spot.
What is the best way to do this in html?
Should I use an image with other images overlaid on top of it?
Should I use html5?
Anybody know of any working examples of a similar nature?
Want to use js, html5, etc to make this work on iphone safari (not native app). App is ruby on rails, so I could make use of some server side features, but would prefer to leverage as much in html/css if possible.
You can use a canvas element to do this. The canvas element allow you to draw images and shapes to it.
To store and retrieve clicks you can use Web Storage (localStorage).
For example - load the image and paint it to canvas:
ONLINE DEMO HERE
HTML:
<canvas id="demo" width="500" height="400"></canvas>
JavaScript:
/// get context for canvas, cache dimension
var ctx = demo.getContext('2d'),
w = demo.width,
h = demo.height,
img = new Image(); /// the image we want to load
/// when done go draw existing marks and start listening for clicks
img.onload = function() {
renderMarks();
demo.onclick = function(e) {
/// convert mouse coord relative to canvas
var rect = demo.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top;
/// store mark
addMark(x, y);
/// redraw everything
renderMarks();
}
}
These are the main functions, this first renders existing marks to canvas on top of the image:
function renderMarks() {
/// re-draw image which also serves to clear canvas
ctx.drawImage(img, 0, 0, w, h);
/// get existing marks from localStorage
var marks = localStorage.getItem('marks'),
i = 0;
/// if any, render them all
if (marks !== null) {
/// localStorage can only store strings
marks = JSON.parse(marks);
/// set color and line width of circle
ctx.strokeStyle = '#f00';
ctx.lineWidth = 3;
/// iterate marks and draw each one
for(;i < marks.length; i++) {
ctx.beginPath();
ctx.arc(marks[i][0], marks[i][1], 30, 0, 2 * Math.PI);
ctx.stroke();
}
}
}
This adds a mark to the collection:
function addMark(x, y) {
/// get existing marks or initialize
var marks = JSON.parse(localStorage.getItem('marks') || '[]');
/// add mark
marks.push([x, y]);
/// update storage
localStorage.setItem('marks', JSON.stringify(marks));
}
(The code can be optimized in various ways but I made it to show the basic principles).
If you now navigate away from the page and come back you will see the marks are rendered again (disclaimer: jsfiddle may or may not give the same page so test locally/in "real" page to be sure).
The circles here can be anything, an image, a different shape and so forth.
To clear the marks simply call:
localStorage.clear();
or if you store other data as well:
localStorage.removeItem('marks');
Well, you can create new images for each spot and when the user click you substitute the original image by the new one. You can do that using CSS or jQuery)
Depending if you are interested in showing areas or the exact x/y coordinates, an image <map> might be of use.
Also check out this stackoverflow question.
I have no working example to show, but I think this qualifies as similar in nature. I am not sure how you'd save the info for recalling state (coming back same session or days/months later?).
I hope this is of some use.
I have a canvas that I'm creating with KineticJS and I am adding transparent PNG images to that canvas. When stacked on top of each other, this makes one image of an outfit with all the different parts.
What I then want to do is allow the user to click on a pattern and then change a specific piece of that outfit with that pattern. So I need to fill in the non-transparent parts of one of the images with that pattern. I found a way to do this that didn't use KineticJS and it looks something like this:
ctx.globalCompositeOperation = 'source-in';
var ptrn = ctx.createPattern(fabricA, 'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 375, 260);
My question is, is there a way to do the same steps outlined above with KineticJS?
Also, I did first try to just do this without using KineticJS, but when I applied the above code to the layer, it filled in all of the images because they were all on the same layer. So I'm guessing that I will need to change my code to either use multiple layers or to add the images to groups in a single layer. Is my thinking right here? And which would be the better option for what I'm trying to accomplish? Multiple Layers? Or Multiple Groups on a single Layer?
Thanks for any help that anyone can provide.
If you want to do custom drawing then use the KineticJS Shape Object
This is a KineticJS object that lets you control exactly how it's drawn.
You create your overlays using your compositing method. Then put that drawing code in a function and give that function to Kinetic Shape's drawFunc.
Here's a skeleton of Kinetic.Shape:
var outfit1 = new Kinetic.Shape({
drawFunc: function(canvas) {
// you are passed a canvas to draw your custom shape on
// so new-up a context and get drawing!
var context = canvas.getContext();
context.beginPath();
// Draw stuff--including your composited overlays
// You can use any canvas.context drawing commands
},
id:"myCustomOutfit"
});
You can get started with an example here: http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-shape-tutorial/
I've been looking all day for a way to procedurally generate 2d texture with text in them so that I can apply them as a texture to a plane. Basically, I want to be able to change what text shows up in my WebGL page without having to just use texture made in an image editing program. I'm aiming to be able to edit the content of the page just as easily as with a totally 2d page, just edit the code and bam, it's there.
The most promising method I've seen to accomplish this is to render the text in a blank canvas with CSS, use that canvas as a texture which ThreeJS makes very easy, and then apply that texture to a plane that I can place wherever in the 3d environment.
I've attempted to accomplish this by adapting this example to my needs: http://jsfiddle.net/sSD65/28/
However, I end up with a totally black page, indicating an error somewhere. An error that I cannot, for the life of me, find and fix. I have a feeling I'm missing something because of my lack of experience with ThreeJS and in fact Javascript in general so I've come here to ask for your help.
I really appreciate any help I can get here.
Here's a link to the page, although I don't think you will be able to view it properly without hosting it locally since I'm loading an image from a folder there, but Python is wonderful for that. Just use Python -m SimpleHTTPServer in the console once you've navigated to that folder and it will host it locally so that you can access it from "http://localhost:8000/homepage.html": https://dl.dropbox.com/u/40043006/WebGLTest.zip
This is a simple code to add text from a canvas as a texture:
//create image
var bitmap = document.createElement('canvas');
var g = bitmap.getContext('2d');
bitmap.width = 100;
bitmap.height = 100;
g.font = 'Bold 20px Arial';
g.fillStyle = 'white';
g.fillText(text, 0, 20);
g.strokeStyle = 'black';
g.strokeText(text, 0, 20);
// canvas contents will be used for a texture
var texture = new THREE.Texture(bitmap)
texture.needsUpdate = true;
it needs some work... like setting the output text size to the canvas' size.
Assuming that I have a WebGL canvas (by calling getContext("experimental-webgl")).
Is there any way to switch context later for using a "2d" one ?
The goal of such thing would be to display a debug BSOD-like when an error happening during rendering.
If it's not possible, then :
Can I embed an html element over a canvas, and force this element to have exactly the same same that the canvas (even if this last is resized) ?
Can I replace an dom node, and update every reference about the old one to reflect the changement ?
[edit] This is my current minimal call code. Canvas is a DOM node containing a canvas which is filled by WebGL API, and callback is a function which process a single frame.
function failure(cvs, e) {
var ctx = cvs.getContext('2d'); // Fail here, returns `null' if cvs.getContext('webgl') has been called
ctx.fillStyle = 'rgb(0, 0, 0)';
ctx.fillRect(0, 0, cvs.width, cvs.height);
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.font = 'bold 12px sans-serif';
ctx.fillText(e.toString(), 0, 0);
}
function foobar(canvas, callback) {
try {
callback();
} catch (e) {
failure(canvas, e);
throw e;
} finally {
requestAnimationFrame(arguments.callee);
}
}
The short answer is pretty much no, according to the spec.
Every canvas has what is called a primary context. This is the first context that is invoked on a canvas. Making a non-primary context on a canvas might do some things on different browsers but I would never, ever depend on it.
I would instead have a second canvas that is overlaid over the first and maintains the same width and height attributes. I would then hide one and unhide the other (or just unhide the 2D one when you want it seen).
OR just use a PNG for simplicity's sake., centered inside of a DIV that also holds the canvas. In other words:
Div container has black background and holds:
PNG (centered)
3D Canvas
Then when you want the error png to be displayed you just hide the 3D canvas (and optionally unhide the PNG)
Rather than have two canvases overlaying, the solution I went with was to replace the existing canvas with a clone of itself.
var newCvs = cvs.cloneNode(false);
cvs.parentNode.replaceChild(newCvs, cvs);
cvs = newCvs;
All the properties of the original canvas will be retained but the context will be freed up to allocate as you wish.