I have a set of relatively simple electrical circuits. Small ones involving just resistors, capacitors, inductors, and trimmers/trimpots (ie: three-terminal variable resistors).
I am trying to find a simple way to render these circuits from the matrix of node-voltage equations. I don't need to calculate current/voltage values (I am already capable of doing that).
I have a basic understanding of how to render 2D shapes in HTML5. At this point, I just need a simple way to place and connect the shapes via lines. I could always do a simple placement, but any suggestions on how to avoid re-inventing the wheel would be great.
Thank you.
Sorry it's been a while, but I've finished the library I promised you. Using it, I can create circuits like these:
I've created a simplified drawing system in javascript for you to use by building a short library.Copy and paste the code for it into your page, and then leave it be. If you want to change it, either ask me (or someone else who know Javascript), or learn it at a website like W3Schools or the Mozilla MDN. The code requires a canvas element with the id "canvas". The code:
"use strict"
var wW=window.innerWidth;
var wH=window.innerHeight;
var canvasHTML=document.getElementById("canvas");
canvasHTML.width=wW;
canvasHTML.height=wH;
var ctx=canvasHTML.getContext("2d");
var ix;
var iy;
var x;
var y;
var d;
var dx;
var dy;
function beginCircuit(a,b)
{
ctx.lineWidth=1.5;
ctx.strokeStyle="#000";
ctx.beginPath();
x=a;
y=b;
d=0;
dx=1;
dy=0;
ix=x;
iy=y;
ctx.moveTo(x,y);
drawWire(50);
drawPower();
}
function endCircuit()
{
ctx.lineTo(ix,iy);
ctx.stroke();
}
function drawWire(l)
{
x+=dx*l;
y+=dy*l;
ctx.lineTo(x,y);
}
function drawPower()
{
var n;
drawWire(10);
n=3;
ctx.moveTo(x+10*dy,y+10*dx);
ctx.lineTo(x-10*dy,y-10*dx);
x+=dx*5;
y+=dy*5;
while(n--)
{
ctx.moveTo(x+15*dy,y+15*dx);
ctx.lineTo(x-15*dy,y-15*dx);
x+=dx*5;
y+=dy*5;
ctx.moveTo(x+10*dy,y+10*dx);
ctx.lineTo(x-10*dy,y-10*dx);
if(n!=0)
{
x+=dx*5;
y+=dy*5;
}
}
ctx.moveTo(x,y);
drawWire(10);
}
function drawCapacitor()
{
drawWire(22.5);
ctx.moveTo(x+10*dy,y+10*dx);
ctx.lineTo(x-10*dy,y-10*dx);
x+=dx*5;
y+=dy*5;
ctx.moveTo(x+10*dy,y+10*dx);
ctx.lineTo(x-10*dy,y-10*dx);
ctx.moveTo(x,y);
drawWire(22.5);
}
function drawInductor()
{
var n,xs,ys;
drawWire(9);
n=4;
xs=1+Math.abs(dy);
ys=1+Math.abs(dx);
x+=dx*6;
y+=dy*6;
ctx.scale(xs,ys);
while(n--)
{
ctx.moveTo(x/xs+5*Math.abs(dx),y/ys+5*dy);
ctx.arc(x/xs,y/ys,5,Math.PI/2*dy,Math.PI+Math.PI/2*dy,1);
x+=6.5*dx;
y+=6.5*dy;
if(n!=0)
{
if(dx>=0)
{
ctx.moveTo(x/xs-5*dx,y/ys-5*dy);
}
ctx.moveTo(x/xs-5*dx,y/ys-5*dy);
ctx.arc(x/xs-6.5/2*dx,y/ys-6.5/2*dy,1.5,Math.PI+Math.PI/2*dy,Math.PI/2*dy,1);
}
}
ctx.moveTo(x/xs-1.75*dx,y/ys-1.75*dy);
ctx.scale(1/xs,1/ys);
ctx.lineTo(x,y);
drawWire(9);
}
function drawTrimmer()
{
ctx.moveTo(x+35*dx-7*dy,y+35*dy-7*dx);
ctx.lineTo(x+15*dx+7*dy,y+15*dy+7*dx);
ctx.moveTo(x+13*dx+4*dy,y+13*dy+4*dx);
ctx.lineTo(x+17*dx+10*dy,y+17*dy+10*dx);
ctx.moveTo(x,y);
drawCapacitor();
}
function drawResistor()
{
var n;
drawWire(10);
n=5;
x+=dx*5;
y+=dy*5;
while(n--)
{
ctx.lineTo(x-5*dy,y-5*dx);
ctx.lineTo(x+5*dy,y+5*dx);
x+=5*dx;
y+=5*dy;
}
ctx.lineTo(x,y);
drawWire(10);
}
function turnClockwise()
{
d++;
dx=Math.cos(1.570796*d);
dy=Math.sin(1.570796*d);
}
function turnCounterClockwise()
{
d--;
dx=Math.cos(1.570796*d);
dy=Math.sin(1.570796*d);
}
Then create a new <script type="text/javascript">....</script> tag and put between the tags your drawing code. Drawing code works like this:
You start by calling the function beginCircuit(x,y). Inside the parenthesis, put the x and y coordinates you want to start your circuit at, like so: beginCircuit(200,100). This will draw a wire, and a battery at the coordinates you specified (in pixels). The battery and wire together take up 100 pixels of space on the screen.
Then, you can call any of the following functions:
drawWire(length)
Draws a wire of the length you specify at the end of the circuit. Takes up length amount of space.
turnClockwise(length)
Turns the direction in which your next command will draw 90° clockwise. Takes up no space.
turnCounterClockwise(length)
Turns the direction in which your next command will draw 90° counter-clockwise. Takes up no space.
drawCapacitor(length)
Draws a capacitor at the end of the circuit. Takes up 50px.
drawInductor(length)
Draws an inductor at the end of the circuit. Takes up 50px.
drawResistor(length)
Draws a resistor at the end of the circuit. Takes up 50px.
drawTrimmer(length)
Draws a resistor at the end of the circuit. Takes up 50px.
When you're done drawing circuitry, use the function endCircuit() to close and then draw the circuit. It will automatically draw a wire from the point where you stopped to the beginning of the circuit.
I know it's a lot to do, but it really is a very easy and flexible way to do this once you understand it. If you want to see this in action, go here: http://jsfiddle.net/mindoftea/ZajVE/. Please give it a shot, and if you have problems, comment about it, please.
Thanks and hope this helps!
Nice works! I'm also in need for teaching purpose which includes Circuits (and Mechanics).
packed it into a class if anybody favor OO style. also added some flexibility to customize symbols, e.g. label etc. http://jsfiddle.net/michael_chnc/q01f2htb/
` /*Basic Circuit symbol toolset, still alot missing credit to: https://stackoverflow.com/users/434421/mindoftea*/
class Circuit { constructor(name = "canvas", ix = 50, iy = 50) {
this.canvas = document.getElementById(name);
this.ctx = canvas.getContext("2d");
this.d = 0; ... }
var cc = new Circuit("canvas", 100, 100); cc.ctx.lineWidth = 2; cc.drawPower(60, 1, "E"); cc.drawCapacitor(60, "C=50 \u03bc"); cc.drawSwitch(40, 1, "S1"); cc.drawInductor(50, 4, "I=40"); cc.turnClockwise(); cc.drawTrimmer(60, "T"); cc.drawResistor(60, 3, 1, "R"); cc.turnClockwise(); cc.drawResistor(160, 3, 2, "R"); cc.save(); cc.turnCounterClockwise(); cc.drawWire(20); cc.turnClockwise(); cc.drawResistor(); cc.turnClockwise(); cc.drawWire(20); cc.restore(); cc.turnClockwise(); cc.drawWire(20); cc.turnCounterClockwise(); cc.drawResistor(50, 5, 2, "R2"); cc.turnCounterClockwise(); cc.drawWire(20); cc.turnClockwise(); cc.drawWire(80); cc.turnClockwise(); cc.drawWire(30); cc.drawSwitch(50, false, "S3");
cc.finish(true); `
Related
I want to make lines but they have sharp edges, e.g. if you use the line to write a word. In Photoshop you can use brushes that are less sharp or you can take a high resolution and zoom out. Is there a nice trick for HTML5 canvas lines, too?
canvas.addEventListener('mousemove', function(e) {
this.style.cursor = 'pointer';
if(this.down) {
with(ctx) {
beginPath();
moveTo(this.X, this.Y);
lineTo(e.pageX , e.pageY );
strokeStyle = red;
ctx.lineWidth=1;
stroke();
}
this.X = e.pageX ;
this.Y = e.pageY ;
}
}, 0);
As you’ve discovered, when you let the user draw a polyline with mousemove you end up with a list of points that draws a very jagged line.
What you need to do is:
Reduce the number of points
Keep the resulting path true to the user’s intended shape.
So you want to go from "before" to "after":
The Ramer-Douglas-Peucker Polygon Simplification Algorithm
You can do this by using the Ramer-Douglas-Peucker (RDP) Polygon Simplification Algorithm. It reduces the “jaggedness” of a polyline while keeping the essence of the intended path.
Here is an overview of how RDP works and what it’s capable of achieving: http://ianqvist.blogspot.com/2010/05/ramer-douglas-peucker-polygon.html
And here is a javascript implimentation of the RDP algorithm thanks to Matthew Taylor: https://gist.github.com/rhyolight/2846020
In Matthew’s implimentation “epsilon” is a number indicating how closely you want to be true to the original “jaggedness”.
First of all sorry for some english mistakes. Portuguese is my first language(I am from Brazil)
Im trying to make a space game from scratch in AS3 and the way to move the ship is like in the game Air Traffic Chief.
I succeed at some point. But when the ship is very fast it start to shake and its not very smooth and clean as I want.
Here is what i have done: http://megaswf.com/s/2437744
As the code is very big so I pasted in pastebin: pastebin.com/1YVZ23WX
I also wrote some english documentation.
This is my first game and my first post here. I really hope you guys can help me.
Thanks in advance.
Edit:
As the code is very big i will try to clarify here.
When the user MouseDown and MouseMove the ship every coordinate is passed to an array.
When the user MouseUP this array is passed to a function that fix the array.
For example: If the distance between two coordinates is greater than 5px, the function creates a coordinate in the middle of the two coordinates.
if I take this function off the problem seen to be solved. But if the user move the mouse very slow it still happens. It also creates a problem that i was trying to solve with that function. as the distance of the two coordinates are very big when the ship arrive in one coordinate most of the line path disappear.
I uploaded a version without the function that fixes the array. http://megaswf.com/s/2437775
I think there is 2 ways for solving this problem
1- Try to fix the noise in the array of coordinates 2- Take off the function that create an coordinate between two points and try to fix the problem of the line path disappear.
Here is the 2 important functions:
this function moves the ship
private function mover():void
{
if (caminhoCoords[0]!=null) // caminhoCoords is the array that contain the path
{
var angulo:Number = Math.atan2(this.y - caminhoCoords[0][1], this.x - caminhoCoords[0][0]);
this.rotation = angulo / (Math.PI / 180);
this.x = this.x - velocidade * (Math.cos(angulo));
this.y = this.y - velocidade * (Math.sin(angulo));
var testex:Number = Math.abs(this.x - caminhoCoords[0][0]); //test to see the distance between the ship and the position in the array
var testey:Number = Math.abs(this.y - caminhoCoords[0][1]);
if (testey<=velocidade+2 && testex<=velocidade+2) // if is velocidade+2 close then go to the next coordnate
{
caminhoCoords.shift();
}
}
}
This function draw the line:
private function desenhaCaminho():void //draw the black Path
{
if(caminhoCoords.length>=1)
{
caminho.graphics.clear();
caminho.graphics.lineStyle(1, 0x000000, 1,true);
caminho.graphics.moveTo(caminhoCoords[0][0],caminhoCoords[0][1]);
for (var i:int = 1; i < caminhoCoords.length; i++)
{
caminho.graphics.lineTo(caminhoCoords[i][0], caminhoCoords[i][1]);
}
}else
{
caminho.graphics.clear();
}
}
Every time the ship arrive in one coordinate is take that coordinate off the array and redraw the array.
Is there a better way of doing that?
I believe if you set your registration point of the plane to the centre and use .snapto(path), it will improve the action.
Judging from just the look of the stuttering, I would guess you need to smooth out the "line" a fair bit. It's probably picking up a lot of noise in the line, which is then translated into the rotation of the plane. Either smooth out the rotation/position of the plane, or the line itself.
I seem to recall something about pass-by-reference and the Greensock TweenLite class. It's the only thing I can think of that is causing this bit of code to be not working as I intend:
for (var i = 0; i < 10; ++i) {
addItem();
}
public function addItem():MovieClip {
var item:MovieClip = getNewItem();
item.y = item.height / 2;
var newPosY = _origHeight - _items.length * item.height;
_items.push(item);
new TweenLite(item, ITEM_DROP_TIME, { y: newPosY } ); trace(newPosY);
addChild(item);
}
The trace is outputting the values I expect: an incremental sequence where each number is greater than the last (by the height of the item). However, what I see visually is that all the items end up at the same location (as if newPosY were the same for all instances of the tween.)
The only thing that comes to mind is that newPosY is being passed by reference, so each instance of the tween is actually referencing the very same value. Am I missing something? Or do I need some kind of closure to isolate the scope of my tween property's value?
EDIT
Suggesting this question be closed as I guess the answer is "No" and the issue was elsewhere in my code. I doubt that any further exposition of the problem would be relevant to others. Thanks to those who responded!
I think your TweenLite syntax is wrong. Try:
TweenLite.to (item, ITEM_DROP_TIME, { y: newPosY } );
So, I'm working on the basics of Actionscript 3; making games and such.
I designed a little space where everything is based on location of boundaries, using pixel-by-pixel movement, etc.
So far, my guy can push a box around, and stops when running into the border, or when try to the push the box when it's against the border.
So, next, I wanted to make it so when I bumped into the other box, it shot forward; a small jump sideways.
I attempted to use this (foolishly) at first:
// When right and left borders collide.
if( (box1.x + box1.width/2) == (box2.x - box2.width/2) ) {
// Nine times through
for (var a:int = 1; a < 10; a++) {
// Adds 1, 2, 3, 4, 5, 4, 3, 2, 1.
if (a <= 5) {
box2.x += a; }
else {
box2.x += a - (a - 5)*2 } } }
Though, using this in the function I had for the movement (constantly checking for keys up, etc) does this all at once.
Where should I start going about a frame-by-frame movement like that? Further more, it's not actually frames in the scene, just in the movement.
This is a massive pile of garbage, I apologize, but any help would be appreciated.
try doing something like: (note ev.target is the box that you assigned the listener to)
var boxJumpDistance:Number = 0;
function jumpBox(ev:Event){
if (boxJumpDistance<= 5) {
ev.target.x += boxJumpDistance; }
else if(boxJumpDistance<=10){
ev.target.x += boxJumpDistance - (boxJumpDistance - 5)*2
}
else{
boxJumpDistance = 0;
ev.target.removeEventListener(Event.ENTER_FRAME, jumpBox);
}
}
then instead of running the loop, just add a listener:
box2.addEventListener(Event.ENTER_FRAME, jumpBox);
although this at the moment only works for a single box at a time (as it is only using one tracking variable for the speed), what you would really want to do is have that function internally to the box class, but im unsure how your structure goes. the other option would be to make an array for the boxes movement perhaps? loop through the array every frame. boxesMoveArray[1] >=5 for box 1, etc.
I want to draw a 3D ball or sphere in HTML 5.0 canvas. I want to understand the Algorithm about how to draw a 3D sphere. Who can share this with me?
You will need to model a sphere, and have it be varying colors so that as it rotates you can see that it is not only a sphere, but being rendered.
Otherwise, a sphere in space, with not point of reference around it looks like a circle, if it is all one solid color.
To start with you will want to try drawing a circle with rectangles, as that is the main primitive you have.
Once you understand how to do that, or create a new primitive, such as a triangle, using the Path method, and create a circle, then you are ready to move it to 3D.
3D is just a trick, as you will take your model, probably generated by an equation, and then flatten it, as you determine which parts will be seen, and then display it.
But, you will want to change the color of the triangles based on how far they are from a source of light, as well as based on the angle of that part to the light source.
This is where you can start to do optimizations, as, if you do this pixel by pixel then you are raytracing. If you have larger blocks, and a point source of light, and the object is rotating but not moving around then you can recalculate how the color changes for each triangle, then it is just a matter of changing colors to simulate rotating.
The algorithm will depend on what simplifications you want to make, so as you gain experience come back and ask, showing what you have done so far.
Here is an example of doing it, and below I copied the 3D sphere part, but please look at the entire article.
function Sphere3D(radius) {
this.point = new Array();
this.color = "rgb(100,0,255)"
this.radius = (typeof(radius) == "undefined") ? 20.0 : radius;
this.radius = (typeof(radius) != "number") ? 20.0 : radius;
this.numberOfVertexes = 0;
// Loop from 0 to 360 degrees with a pitch of 10 degrees ...
for(alpha = 0; alpha <= 6.28; alpha += 0.17) {
p = this.point[this.numberOfVertexes] = new Point3D();
p.x = Math.cos(alpha) * this.radius;
p.y = 0;
p.z = Math.sin(alpha) * this.radius;
this.numberOfVertexes++;
}
// Loop from 0 to 90 degrees with a pitch of 10 degrees ...
// (direction = 1)
// Loop from 0 to 90 degrees with a pitch of 10 degrees ...
// (direction = -1)
for(var direction = 1; direction >= -1; direction -= 2) {
for(var beta = 0.17; beta < 1.445; beta += 0.17) {
var radius = Math.cos(beta) * this.radius;
var fixedY = Math.sin(beta) * this.radius * direction;
for(var alpha = 0; alpha < 6.28; alpha += 0.17) {
p = this.point[this.numberOfVertexes] = new Point3D();
p.x = Math.cos(alpha) * radius;
p.y = fixedY;
p.z = Math.sin(alpha) * radius;
this.numberOfVertexes++;
}
}
}
}
u can try with three.js library , which abstracts a lot of code from core webgl programming. Include three.js library in your html from three.js lib.
u can use canvas renderer for safari browser , webgl works for chrome
please find the JS FIDDLE FOR SPHERE
var camera, scene, material, mesh, geometry, renderer
function drawSphere() {
init();
animate();
}
function init() {
// camera
scene = new THREE.Scene()
camera = new THREE.PerspectiveCamera(50, window.innerWidth / innerHeight, 1, 1000);
camera.position.z = 300;
scene.add(camera);
// sphere object
var radius = 50,
segments = 10,
rings = 10;
geometry = new THREE.SphereGeometry(radius, segments, rings);
material = new THREE.MeshNormalMaterial({
color: 0x002288
});
mesh = new THREE.Mesh(geometry, material);
//scene
;
scene.add(mesh);
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
mesh.rotation.x += .01;
mesh.rotation.y += .02;
renderer.render(scene, camera);
}
// fn callin
drawSphere();
Update: This code is quite old and limited. There are libraries for doing 3D spheres now: http://techslides.com/d3-globe-with-canvas-webgl-and-three-js/
Over ten years ago I wrote a Java applet to render a textured sphere by actually doing the math to work out where the surface of the sphere was in the scene (not using triangles).
I've rewritten it in JavaScript for canvas and I've got a demo rendering the earth as a sphere:
(source: haslers.info)
I get around 22 fps on my machine. Which is about as fast as the Java version it was based on renders at, if not a little faster!
Now it's a long time since I wrote the Java code - and it was quite obtuse - so I don't really remember exactly how it works, I've just ported it JavaScript. However this is from a slow version of the code and I'm not sure if the faster version was due to optimisations in the Java methods I used to manipulate pixels or from speedups in the math it does to work out which pixel to render from the texture. I was also corresponding at the time with someone who had a similar applet that was much faster than mine but again I don't know if any of the speed improvements they had would be possible in JavaScript as it may have relied on Java libraries. (I never saw their code so I don't know how they did it.)
So it may be possible to improve on the speed. But this works well as a proof of concept.
I'll have a go at converting my faster version some time to see if I can get any speed improvements into the JavaScript version.
Well, an image of a sphere will always have a circular shape on your screen, so the only thing that matters is the shading. This will be determined by where you place your light source.
As for algorithms, ray tracing is the simplest, but also the slowest by far — so you probably wouldn't want to use it to do anything very complicated in a <CANVAS> (especially given the lack of graphics acceleration available in that environment), but it might be fast enough if you just wanted to do a single sphere.