Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
9d01c286
Commit
9d01c286
authored
Jan 06, 2012
by
Piotr Mitros
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New schematic.js from cjt
parent
213d1061
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
583 additions
and
93 deletions
+583
-93
js/schematic.js
+583
-93
No files found.
js/schematic.js
View file @
9d01c286
...
...
@@ -13,7 +13,8 @@
// other attributes you can add to the input tag:
// width -- width in pixels of diagram
// height -- height in pixels of diagram
// parts -- comma-separated list of parts for parts bin (see parts_map)
// parts -- comma-separated list of parts for parts bin (see parts_map),
// parts="" disables editing of diagram
// JSON schematic representation:
// sch := [part, part, ...]
...
...
@@ -70,7 +71,7 @@ schematic = (function() {
annotation_style
=
'rgb(255,64,64)'
;
// color for diagram annotations
property_size
=
5
;
// point size for Component property text
annotation_size
=
8
;
// point size for diagram annotations
annotation_size
=
7
;
// point size for diagram annotations
// list of all the defined parts
parts_map
=
{
...
...
@@ -84,6 +85,7 @@ schematic = (function() {
'd'
:
[
Diode
,
'Diode'
],
'n'
:
[
NFet
,
'NFet'
],
'p'
:
[
PFet
,
'PFet'
],
's'
:
[
Probe
,
'Scope Probe'
],
};
// fix cursor bug in Chrome (default behavior: change to text cursor
...
...
@@ -105,10 +107,35 @@ schematic = (function() {
this
.
grid
=
8
;
this
.
scale
=
2
;
this
.
origin_x
=
0
;
this
.
origin_y
=
0
;
this
.
origin_x
=
input
.
getAttribute
(
"origin_x"
);
if
(
this
.
origin_x
==
undefined
)
this
.
origin_x
=
0
;
this
.
origin_y
=
input
.
getAttribute
(
"origin_y"
);
if
(
this
.
origin_y
==
undefined
)
this
.
origin_y
=
0
;
this
.
clipboard
=
undefined
;
// use user-supplied list of parts if supplied
// else just populate parts bin with all the parts
this
.
edits_allowed
=
true
;
var
parts
=
input
.
getAttribute
(
'parts'
);
if
(
parts
==
undefined
)
{
parts
=
new
Array
();
for
(
var
p
in
parts_map
)
parts
.
push
(
p
);
}
else
if
(
parts
==
''
)
{
this
.
edits_allowed
=
false
;
parts
=
[];
}
else
parts
=
parts
.
split
(
','
);
// use user-supplied list of analyses, otherwise provide them all
// analyses="" means no analyses
var
analyses
=
input
.
getAttribute
(
'analyses'
);
if
(
analyses
==
undefined
)
analyses
=
[
'dc'
,
'ac'
,
'tran'
];
else
if
(
analyses
==
''
)
analyses
=
[];
else
analyses
=
analyses
.
split
(
','
);
if
(
parts
.
length
==
0
&&
analyses
.
length
==
0
)
this
.
diagram_only
=
true
;
else
this
.
diagram_only
=
false
;
if
(
!
this
.
diagram_only
)
{
// start with a background element with normal positioning
this
.
background
=
document
.
createElement
(
'canvas'
);
this
.
background
.
style
.
backgroundColor
=
background_style
;
...
...
@@ -116,27 +143,28 @@ schematic = (function() {
this
.
background
.
style
.
borderWidth
=
'2px'
;
this
.
status_div
=
document
.
createElement
(
'div'
);
//this.status_div.style.borderStyle = 'solid';
//this.status_div.style.borderWidth = '1px';
this
.
status_div
.
style
.
position
=
'absolute'
;
this
.
status_div
.
style
.
padding
=
'2px'
;
//this.status_div.style.backgroundColor = element_style;
this
.
status
=
document
.
createTextNode
(
''
);
this
.
status_div
.
appendChild
(
this
.
status
);
}
this
.
connection_points
=
new
Array
();
// location string => list of cp's
this
.
components
=
[];
// this is where schematic is rendered
this
.
canvas
=
document
.
createElement
(
'canvas'
);
if
(
!
this
.
diagram_only
)
{
this
.
canvas
.
tabIndex
=
1
;
// so we get keystrokes
this
.
canvas
.
style
.
borderStyle
=
'solid'
;
this
.
canvas
.
style
.
borderWidth
=
'1px'
;
this
.
canvas
.
style
.
borderColor
=
grid_style
;
this
.
canvas
.
style
.
position
=
'absolute'
;
this
.
canvas
.
style
.
outline
=
'none'
;
}
this
.
canvas
.
schematic
=
this
;
if
(
this
.
edits_allowed
)
{
this
.
canvas
.
addEventListener
(
'mousemove'
,
schematic_mouse_move
,
false
);
this
.
canvas
.
addEventListener
(
'mouseover'
,
schematic_mouse_enter
,
false
);
this
.
canvas
.
addEventListener
(
'mouseout'
,
schematic_mouse_leave
,
false
);
...
...
@@ -145,29 +173,38 @@ schematic = (function() {
this
.
canvas
.
addEventListener
(
'dblclick'
,
schematic_double_click
,
false
);
this
.
canvas
.
addEventListener
(
'keydown'
,
schematic_key_down
,
false
);
this
.
canvas
.
addEventListener
(
'keyup'
,
schematic_key_up
,
false
);
}
// toolbar
this
.
tools
=
new
Array
();
this
.
toolbar
=
[];
if
(
this
.
edits_allowed
)
{
this
.
tools
[
'cut'
]
=
this
.
add_tool
(
cut_icon
,
'Cut: move selected components from diagram to the clipboard'
,
this
.
cut
);
this
.
tools
[
'copy'
]
=
this
.
add_tool
(
copy_icon
,
'Copy: copy selected components into the clipboard'
,
this
.
copy
);
this
.
tools
[
'paste'
]
=
this
.
add_tool
(
paste_icon
,
'Paste: copy clipboard into the diagram'
,
this
.
paste
);
this
.
toolbar
.
push
(
null
);
// spacer
}
// simulation interface if cktsim.js is loaded
if
(
typeof
cktsim
!=
'undefined'
)
{
this
.
toolbar
.
push
(
null
);
// spacer
if
(
analyses
.
indexOf
(
'dc'
)
!=
-
1
)
{
this
.
tools
[
'dc'
]
=
this
.
add_tool
(
'DC'
,
'DC Analysis'
,
this
.
dc_analysis
);
//this.tools['ac'] = this.add_tool('AC','AC Small-Signal Analysis',this.ac_analysis);
//this.tools['tran'] = this.add_tool('TRAN','Transient Analysis',this.transient_analysis);
this
.
enable_tool
(
'dc'
,
true
);
//this.enable_tool('ac',true);
//this.enable_tool('tran',true);
}
// make the canvas "clickable" by registering a dummy click handler
// this should make things work on the iPad
this
.
canvas
.
addEventListener
(
'click'
,
function
(){},
false
);
if
(
analyses
.
indexOf
(
'ac'
)
!=
-
1
)
{
this
.
tools
[
'ac'
]
=
this
.
add_tool
(
'AC'
,
'AC Small-Signal Analysis'
,
this
.
ac_analysis
);
this
.
enable_tool
(
'ac'
,
true
);
this
.
ac_npts
=
'5'
;
// default values for AC Analysis
this
.
ac_fstart
=
'10'
;
this
.
ac_fstop
=
'10MEG'
;
}
if
(
analyses
.
indexOf
(
'tran'
)
!=
-
1
)
{
//this.tools['tran'] = this.add_tool('TRAN','Transient Analysis',this.tran_analysis);
//this.enable_tool('tran',true);
}
}
this
.
dragging
=
false
;
this
.
drawCursor
=
false
;
...
...
@@ -188,15 +225,6 @@ schematic = (function() {
// repaint simply draws this buffer and then adds selected elements on top
this
.
bg_image
=
document
.
createElement
(
'canvas'
);
// use user-supplied list of parts if supplied
// else just populate parts bin with all the parts
var
parts
=
input
.
getAttribute
(
'parts'
);
if
(
parts
)
parts
=
parts
.
split
(
','
);
else
{
parts
=
new
Array
();
for
(
var
p
in
parts_map
)
parts
.
push
(
p
);
}
// now add the parts to the parts bin
var
parts_left
=
this
.
width
+
3
+
background_margin
;
var
parts_top
=
background_margin
;
...
...
@@ -209,15 +237,17 @@ schematic = (function() {
}
// add all elements to the DOM
if
(
!
this
.
diagram_only
)
{
this
.
div
.
appendChild
(
this
.
background
);
for
(
var
i
=
0
;
i
<
this
.
toolbar
.
length
;
i
++
)
{
var
tool
=
this
.
toolbar
[
i
];
if
(
tool
!=
null
)
this
.
div
.
appendChild
(
tool
);
}
this
.
div
.
appendChild
(
this
.
canvas
);
this
.
div
.
appendChild
(
this
.
status_div
);
for
(
var
i
=
0
;
i
<
this
.
parts_bin
.
length
;
i
++
)
this
.
div
.
appendChild
(
this
.
parts_bin
[
i
].
canvas
);
}
this
.
div
.
appendChild
(
this
.
canvas
);
input
.
parentNode
.
insertBefore
(
this
.
div
,
input
.
nextSibling
);
// make sure other code can find us!
...
...
@@ -243,21 +273,28 @@ schematic = (function() {
// limit the shrinkage factor
w
=
Math
.
max
(
w
,
120
);
h
=
Math
.
max
(
h
,
120
);
this
.
width
=
w
;
this
.
height
=
h
;
this
.
bg_image
.
width
=
w
;
this
.
bg_image
.
height
=
h
;
if
(
this
.
diagram_only
)
{
this
.
canvas
.
width
=
w
;
this
.
canvas
.
height
=
h
;
this
.
redraw_background
();
// redraw diagram
return
;
}
this
.
min_x
=
0
;
this
.
min_y
=
0
;
this
.
max_x
=
w
/
this
.
scale
;
this
.
max_y
=
h
/
this
.
scale
;
var
left
=
2
*
background_margin
;
// space to the left
var
left
,
top
;
// start with tool bar
var
top
=
background_margin
;
left
=
2
*
background_margin
;
// space to the left
top
=
background_margin
;
var
max_height
=
0
;
if
(
this
.
toolbar
.
length
>
0
)
{
tool_left
=
left
;
...
...
@@ -604,11 +641,7 @@ schematic = (function() {
//
////////////////////////////////////////////////////////////////////////////////
Schematic
.
prototype
.
dc_analysis
=
function
()
{
// remove any previous annotations
this
.
operating_point
=
undefined
;
this
.
redraw
();
Schematic
.
prototype
.
extract_circuit
=
function
()
{
// give all the circuit nodes a name, extract netlist
this
.
label_connection_points
();
var
netlist
=
this
.
json
();
...
...
@@ -617,6 +650,16 @@ schematic = (function() {
var
ckt
=
new
cktsim
.
Circuit
();
ckt
.
load_netlist
(
netlist
);
return
ckt
;
}
Schematic
.
prototype
.
dc_analysis
=
function
()
{
// remove any previous annotations
this
.
unselect_all
(
-
1
);
this
.
redraw_background
();
var
ckt
=
this
.
extract_circuit
();
// run the analysis
this
.
operating_point
=
ckt
.
dc
();
...
...
@@ -624,7 +667,88 @@ schematic = (function() {
this
.
redraw
();
}
// return a list of [color,node_label] for each probe in the diagram
Schematic
.
prototype
.
find_probes
=
function
()
{
var
result
=
[];
for
(
var
i
=
this
.
components
.
length
-
1
;
i
>=
0
;
--
i
)
{
var
c
=
this
.
components
[
i
];
if
(
c
.
type
==
's'
)
result
.
push
(
c
.
probe_info
());
}
return
result
;
}
Schematic
.
prototype
.
ac_analysis
=
function
()
{
this
.
unselect_all
(
-
1
);
this
.
redraw_background
();
var
npts_lbl
=
'Number of points/decade'
;
var
fstart_lbl
=
'Starting frequency (Hz)'
;
var
fstop_lbl
=
'Ending frequency (Hz)'
;
if
(
this
.
find_probes
().
length
==
0
)
{
this
.
message
(
"AC Analysis: there are no scope probes in the diagram!"
);
return
;
}
var
fields
=
new
Array
();
fields
[
npts_lbl
]
=
build_input
(
'text'
,
10
,
this
.
ac_npts
);
fields
[
fstart_lbl
]
=
build_input
(
'text'
,
10
,
this
.
ac_fstart
);
fields
[
fstop_lbl
]
=
build_input
(
'text'
,
10
,
this
.
ac_fstop
);
var
content
=
build_table
(
fields
);
content
.
fields
=
fields
;
content
.
sch
=
this
;
this
.
dialog
(
'AC Analysis'
,
content
,
function
(
content
)
{
var
sch
=
content
.
sch
;
var
ckt
=
sch
.
extract_circuit
();
// retrieve parameters, remember for next time
sch
.
ac_npts
=
content
.
fields
[
npts_lbl
].
value
;
sch
.
ac_fstart
=
content
.
fields
[
fstart_lbl
].
value
;
sch
.
ac_fstop
=
content
.
fields
[
fstop_lbl
].
value
;
// run the analysis
var
results
=
ckt
.
ac
(
ckt
.
parse_number
(
sch
.
ac_npts
),
ckt
.
parse_number
(
sch
.
ac_fstart
),
ckt
.
parse_number
(
sch
.
ac_fstop
));
if
(
typeof
results
==
'string'
)
sch
.
message
(
results
);
else
{
var
x_values
=
results
[
'frequencies'
];
// x axis will be a log scale
for
(
var
i
=
x_values
.
length
-
1
;
i
>=
0
;
--
i
)
x_values
[
i
]
=
Math
.
log
(
x_values
[
i
])
/
Math
.
LN10
;
// set up plot values for each node with a probe
var
y_values
=
[];
// list of [color, result_array]
var
probes
=
sch
.
find_probes
();
for
(
var
i
=
probes
.
length
-
1
;
i
>=
0
;
--
i
)
{
var
color
=
probes
[
i
][
0
];
var
label
=
probes
[
i
][
1
];
var
v
=
results
[
label
];
// convert values into dB relative to max value
var
v_max
=
-
Infinity
;
for
(
var
j
=
v
.
length
-
1
;
j
>=
0
;
--
j
)
{
v
[
j
]
=
Math
.
abs
(
v
[
j
]);
if
(
v
[
j
]
>
v_max
)
v_max
=
v
[
j
];
}
for
(
var
j
=
v
.
length
-
1
;
j
>=
0
;
--
j
)
// convert each value to dB relative to max
v
[
j
]
=
20.0
*
Math
.
log
(
v
[
j
]
/
v_max
)
/
Math
.
LN10
;
y_values
.
push
([
color
,
v
]);
}
// graph the result and display in a window
var
graph
=
sch
.
graph
(
x_values
,
y_values
,
'log(Frequency)'
,
'dB'
);
sch
.
window
(
'Results of AC Analysis'
,
graph
);
}
})
}
Schematic
.
prototype
.
transient_analysis
=
function
()
{
...
...
@@ -643,14 +767,13 @@ schematic = (function() {
var
w
=
this
.
bg_image
.
width
;
var
h
=
this
.
bg_imageheight
;
c
.
lineCap
=
'round'
;
if
(
!
this
.
diagram_only
)
{
// paint background color
c
.
fillStyle
=
element_style
;
c
.
fillRect
(
0
,
0
,
this
.
width
,
this
.
height
);
// border
//c.strokeStyle = "rgb(0,0,0)";
//c.strokeRect(0,0,this.width,this.height);
// grid
c
.
strokeStyle
=
grid_style
;
var
first_x
=
this
.
min_x
;
...
...
@@ -661,6 +784,7 @@ schematic = (function() {
this
.
draw_line
(
c
,
i
,
first_y
,
i
,
last_y
,
0.1
);
for
(
var
i
=
first_y
;
i
<
last_y
;
i
+=
this
.
grid
)
this
.
draw_line
(
c
,
first_x
,
i
,
last_x
,
i
,
0.1
);
}
// unselected components
for
(
var
i
=
this
.
components
.
length
-
1
;
i
>=
0
;
--
i
)
{
...
...
@@ -720,6 +844,9 @@ schematic = (function() {
// display operating point results
if
(
this
.
operating_point
)
{
if
(
typeof
this
.
operating_point
==
'string'
)
this
.
message
(
this
.
operating_point
);
else
{
// make a copy of the operating_point info so we can mess with it
var
temp
=
new
Array
();
for
(
var
i
in
this
.
operating_point
)
temp
[
i
]
=
this
.
operating_point
[
i
];
...
...
@@ -729,6 +856,7 @@ schematic = (function() {
for
(
var
location
in
this
.
connection_points
)
(
this
.
connection_points
[
location
])[
0
].
display_voltage
(
c
,
temp
);
}
}
// finally overlay cursor
if
(
this
.
drawCursor
&&
this
.
draw_cursor
)
{
...
...
@@ -745,6 +873,14 @@ schematic = (function() {
this
.
draw_line
(
c
,
x
,
y
-
this
.
grid
,
x
,
y
+
this
.
grid
,
1
);
}
Schematic
.
prototype
.
moveTo
=
function
(
c
,
x
,
y
)
{
c
.
moveTo
((
x
-
this
.
origin_x
)
*
this
.
scale
,(
y
-
this
.
origin_y
)
*
this
.
scale
);
}
Schematic
.
prototype
.
lineTo
=
function
(
c
,
x
,
y
)
{
c
.
lineTo
((
x
-
this
.
origin_x
)
*
this
.
scale
,(
y
-
this
.
origin_y
)
*
this
.
scale
);
}
Schematic
.
prototype
.
draw_line
=
function
(
c
,
x1
,
y1
,
x2
,
y2
,
width
)
{
c
.
lineWidth
=
width
*
this
.
scale
;
c
.
beginPath
();
...
...
@@ -1087,6 +1223,7 @@ schematic = (function() {
// div to hold the content
var
body
=
document
.
createElement
(
'div'
);
content
.
style
.
marginBotton
=
'5px'
;
body
.
appendChild
(
content
);
body
.
style
.
padding
=
'5px'
;
dialog
.
appendChild
(
body
);
...
...
@@ -1146,6 +1283,50 @@ schematic = (function() {
//
////////////////////////////////////////////////////////////////////////////////
// build a 2-column HTML table from an associative array (keys as text in
// column 1, values in column 2).
function
build_table
(
a
)
{
var
tbl
=
document
.
createElement
(
'table'
);
// build a row for each element in associative array
for
(
var
i
in
a
)
{
var
label
=
document
.
createTextNode
(
i
+
': '
);
var
col1
=
document
.
createElement
(
'td'
);
col1
.
appendChild
(
label
);
var
col2
=
document
.
createElement
(
'td'
);
col2
.
appendChild
(
a
[
i
]);
var
row
=
document
.
createElement
(
'tr'
);
row
.
appendChild
(
col1
);
row
.
appendChild
(
col2
);
row
.
style
.
verticalAlign
=
'center'
;
tbl
.
appendChild
(
row
);
}
return
tbl
;
}
// build an input field
function
build_input
(
type
,
size
,
value
)
{
var
input
=
document
.
createElement
(
'input'
);
input
.
type
=
type
;
input
.
size
=
size
;
if
(
value
==
undefined
)
input
.
value
=
''
;
else
input
.
value
=
value
.
toString
();
return
input
;
}
// build a select widget using the strings found in the options array
function
build_select
(
options
,
selected
)
{
var
select
=
document
.
createElement
(
'select'
);
for
(
var
i
=
0
;
i
<
options
.
length
;
i
++
)
{
var
option
=
document
.
createElement
(
'option'
);
option
.
text
=
options
[
i
];
select
.
add
(
option
);
if
(
options
[
i
]
==
selected
)
select
.
selectedIndex
=
i
;
}
return
select
;
}
Schematic
.
prototype
.
window
=
function
(
title
,
content
)
{
// create the div for the top level of the window
var
win
=
document
.
createElement
(
'div'
);
...
...
@@ -1299,6 +1480,8 @@ schematic = (function() {
Schematic
.
prototype
.
enable_tool
=
function
(
tname
,
which
)
{
var
tool
=
this
.
tools
[
tname
];
if
(
tool
!=
undefined
)
{
tool
.
style
.
opacity
=
which
?
1.0
:
0.2
;
tool
.
enabled
=
which
;
...
...
@@ -1308,6 +1491,7 @@ schematic = (function() {
tool
.
sch
.
message
(
''
);
}
}
}
// highlight tool button by turning on border, changing background
function
tool_enter
(
event
)
{
...
...
@@ -1351,6 +1535,239 @@ schematic = (function() {
///////////////////////////////////////////////////////////////////////////////
//
// Graphing
//
///////////////////////////////////////////////////////////////////////////////
// add dashed lines!
// from http://davidowens.wordpress.com/2010/09/07/html-5-canvas-and-dashed-lines/
CanvasRenderingContext2D
.
prototype
.
dashedLineTo
=
function
(
fromX
,
fromY
,
toX
,
toY
,
pattern
)
{
// Our growth rate for our line can be one of the following:
// (+,+), (+,-), (-,+), (-,-)
// Because of this, our algorithm needs to understand if the x-coord and
// y-coord should be getting smaller or larger and properly cap the values
// based on (x,y).
var
lt
=
function
(
a
,
b
)
{
return
a
<=
b
;
};
var
gt
=
function
(
a
,
b
)
{
return
a
>=
b
;
};
var
capmin
=
function
(
a
,
b
)
{
return
Math
.
min
(
a
,
b
);
};
var
capmax
=
function
(
a
,
b
)
{
return
Math
.
max
(
a
,
b
);
};
var
checkX
=
{
thereYet
:
gt
,
cap
:
capmin
};
var
checkY
=
{
thereYet
:
gt
,
cap
:
capmin
};
if
(
fromY
-
toY
>
0
)
{
checkY
.
thereYet
=
lt
;
checkY
.
cap
=
capmax
;
}
if
(
fromX
-
toX
>
0
)
{
checkX
.
thereYet
=
lt
;
checkX
.
cap
=
capmax
;
}
this
.
moveTo
(
fromX
,
fromY
);
var
offsetX
=
fromX
;
var
offsetY
=
fromY
;
var
idx
=
0
,
dash
=
true
;
while
(
!
(
checkX
.
thereYet
(
offsetX
,
toX
)
&&
checkY
.
thereYet
(
offsetY
,
toY
)))
{
var
ang
=
Math
.
atan2
(
toY
-
fromY
,
toX
-
fromX
);
var
len
=
pattern
[
idx
];
offsetX
=
checkX
.
cap
(
toX
,
offsetX
+
(
Math
.
cos
(
ang
)
*
len
));
offsetY
=
checkY
.
cap
(
toY
,
offsetY
+
(
Math
.
sin
(
ang
)
*
len
));
if
(
dash
)
this
.
lineTo
(
offsetX
,
offsetY
);
else
this
.
moveTo
(
offsetX
,
offsetY
);
idx
=
(
idx
+
1
)
%
pattern
.
length
;
dash
=
!
dash
;
}
};
// given a range of values, return a new range [vmin',vmax'] where the limits
// have been chosen "nicely". Taken from matplotlib.ticker.LinearLocator
function
view_limits
(
vmin
,
vmax
)
{
var
log_range
=
Math
.
log
(
vmax
-
vmin
)
/
Math
.
LN10
;
var
exponent
=
Math
.
floor
(
log_range
);
//if (log_range - exponent < 0.5) exponent -= 1;
var
scale
=
Math
.
pow
(
10
,
-
exponent
);
vmin
=
Math
.
floor
(
scale
*
vmin
)
/
scale
;
vmax
=
Math
.
ceil
(
scale
*
vmax
)
/
scale
;
return
[
vmin
,
vmax
,
1.0
/
scale
];
}
// x_values is an array of x coordinates for each of the plots
// y_values is an array of [color, value_array], one entry for each plot
Schematic
.
prototype
.
graph
=
function
(
x_values
,
y_values
,
x_legend
,
y_legend
)
{
var
pwidth
=
400
;
// dimensions of actual plot
var
pheight
=
300
;
// dimensions of actual plot
var
left_margin
=
55
;
var
top_margin
=
25
;
var
right_margin
=
25
;
var
bottom_margin
=
45
;
var
tick_length
=
5
;
var
pattern
=
[
1
,
2
];
var
w
=
pwidth
+
left_margin
+
right_margin
;
var
h
=
pheight
+
top_margin
+
bottom_margin
;
var
canvas
=
document
.
createElement
(
'canvas'
);
canvas
.
width
=
w
;
canvas
.
height
=
h
;
// the graph itself will be drawn here and this image will be copied
// onto canvas, where it can be overlayed with mouse cursors, etc.
var
bg_image
=
document
.
createElement
(
'canvas'
);
bg_image
.
width
=
w
;
bg_image
.
height
=
h
;
canvas
.
bg_image
=
bg_image
;
// so we can find it during event handling
// start by painting an opaque background
var
c
=
bg_image
.
getContext
(
'2d'
);
c
.
fillStyle
=
background_style
;
c
.
fillRect
(
0
,
0
,
w
,
h
);
c
.
fillStyle
=
element_style
;
c
.
fillRect
(
left_margin
,
top_margin
,
pwidth
,
pheight
);
// figure out scaling for plots
var
x_min
=
array_min
(
x_values
);
var
x_max
=
array_max
(
x_values
);
var
x_limits
=
view_limits
(
x_min
,
x_max
);
x_min
=
x_limits
[
0
];
x_max
=
x_limits
[
1
];
var
x_scale
=
pwidth
/
(
x_max
-
x_min
);
function
plot_x
(
x
)
{
return
(
x
-
x_min
)
*
x_scale
+
left_margin
;
}
// draw x grid
c
.
strokeStyle
=
grid_style
;
c
.
lineWidth
=
1
;
c
.
fillStyle
=
normal_style
;
c
.
font
=
'10pt sans-serif'
;
c
.
textAlign
=
'center'
;
c
.
textBaseline
=
'top'
;
var
end
=
top_margin
+
pheight
;
for
(
var
x
=
x_min
;
x
<=
x_max
;
x
+=
x_limits
[
2
])
{
var
temp
=
plot_x
(
x
)
+
0.5
;
// keep lines crisp!
// grid line
c
.
beginPath
();
if
(
x
==
x_min
)
{
c
.
moveTo
(
temp
,
top_margin
);
c
.
lineTo
(
temp
,
end
);
}
else
c
.
dashedLineTo
(
temp
,
top_margin
,
temp
,
end
,
pattern
);
c
.
stroke
();
// tick mark
c
.
beginPath
();
c
.
moveTo
(
temp
,
end
);
c
.
lineTo
(
temp
,
end
+
tick_length
);
c
.
stroke
();
c
.
fillText
(
x
.
toString
(),
temp
,
end
+
tick_length
);
}
var
y_min
=
Infinity
;
var
y_max
=
-
Infinity
;
var
plot
;
for
(
plot
=
y_values
.
length
-
1
;
plot
>=
0
;
--
plot
)
{
var
values
=
y_values
[
plot
][
1
];
var
temp
=
array_min
(
values
);
if
(
temp
<
y_min
)
y_min
=
temp
;
temp
=
array_max
(
values
);
if
(
temp
>
y_max
)
y_max
=
temp
;
}
var
y_limits
=
view_limits
(
y_min
,
y_max
);
y_min
=
y_limits
[
0
];
y_max
=
y_limits
[
1
];
var
y_scale
=
pheight
/
(
y_max
-
y_min
);
function
plot_y
(
y
)
{
return
(
y_max
-
y
)
*
y_scale
+
top_margin
;
}
// draw y grid
c
.
textAlign
=
'right'
;
c
.
textBaseline
=
'middle'
;
for
(
var
y
=
y_min
;
y
<=
y_max
;
y
+=
y_limits
[
2
])
{
var
temp
=
plot_y
(
y
)
+
0.5
;
// keep lines crisp!
// grid line
c
.
beginPath
();
if
(
y
==
y_min
)
{
c
.
moveTo
(
left_margin
,
temp
);
c
.
lineTo
(
left_margin
+
pwidth
,
temp
);
}
else
c
.
dashedLineTo
(
left_margin
,
temp
,
left_margin
+
pwidth
,
temp
,
pattern
);
c
.
stroke
();
// tick mark
c
.
beginPath
();
c
.
moveTo
(
left_margin
-
tick_length
,
temp
);
c
.
lineTo
(
left_margin
,
temp
);
c
.
stroke
();
c
.
fillText
(
y
.
toString
(),
left_margin
-
tick_length
-
2
,
temp
);
}
// now draw each plot
var
x
,
y
;
c
.
lineWidth
=
3
;
for
(
plot
=
y_values
.
length
-
1
;
plot
>=
0
;
--
plot
)
{
c
.
strokeStyle
=
probe_colors_rgb
[
y_values
[
plot
][
0
]];
var
values
=
y_values
[
plot
][
1
];
c
.
beginPath
();
x
=
plot_x
(
x_values
[
0
]);
y
=
plot_y
(
values
[
0
]);
c
.
moveTo
(
x
,
y
);
for
(
var
i
=
1
;
i
<
x_values
.
length
;
i
++
)
{
x
=
plot_x
(
x_values
[
i
]);
y
=
plot_y
(
values
[
i
]);
c
.
lineTo
(
x
,
y
);
}
c
.
stroke
();
}
// draw legends
c
.
font
=
'12pt sans-serif'
;
c
.
textAlign
=
'center'
;
c
.
textBaseline
=
'bottom'
;
c
.
fillText
(
x_legend
,
left_margin
+
pwidth
/
2
,
h
-
5
);
c
.
textBaseline
=
'top'
;
c
.
save
();
c
.
translate
(
5
,
top_margin
+
pheight
/
2
);
c
.
rotate
(
-
Math
.
PI
/
2
);
c
.
fillText
(
y_legend
,
0
,
0
);
c
.
restore
();
// return our masterpiece
redraw_plot
(
canvas
);
return
canvas
;
}
function
array_max
(
a
)
{
max
=
-
Infinity
;
for
(
var
i
=
a
.
length
-
1
;
i
>=
0
;
--
i
)
if
(
a
[
i
]
>
max
)
max
=
a
[
i
];
return
max
;
}
function
array_min
(
a
)
{
min
=
Infinity
;
for
(
var
i
=
a
.
length
-
1
;
i
>=
0
;
--
i
)
if
(
a
[
i
]
<
min
)
min
=
a
[
i
];
return
min
;
}
function
redraw_plot
(
canvas
)
{
var
c
=
canvas
.
getContext
(
'2d'
);
c
.
drawImage
(
canvas
.
bg_image
,
0
,
0
);
}
///////////////////////////////////////////////////////////////////////////////
//
// Parts bin
//
////////////////////////////////////////////////////////////////////////////////
...
...
@@ -1430,6 +1847,14 @@ schematic = (function() {
// no connection points in the parts bin
}
Part
.
prototype
.
moveTo
=
function
(
c
,
x
,
y
)
{
c
.
moveTo
((
x
-
this
.
origin_x
)
*
this
.
scale
,(
y
-
this
.
origin_y
)
*
this
.
scale
);
}
Part
.
prototype
.
lineTo
=
function
(
c
,
x
,
y
)
{
c
.
lineTo
((
x
-
this
.
origin_x
)
*
this
.
scale
,(
y
-
this
.
origin_y
)
*
this
.
scale
);
}
Part
.
prototype
.
draw_line
=
function
(
c
,
x1
,
y1
,
x2
,
y2
,
width
)
{
c
.
lineWidth
=
width
*
this
.
scale
;
c
.
beginPath
();
...
...
@@ -1552,8 +1977,9 @@ schematic = (function() {
//
////////////////////////////////////////////////////////////////////////////////
function
Component
(
x
,
y
,
rotation
)
{
function
Component
(
type
,
x
,
y
,
rotation
)
{
this
.
sch
=
undefined
;
this
.
type
=
type
;
this
.
x
=
x
;
this
.
y
=
y
;
this
.
rotation
=
rotation
;
...
...
@@ -1666,6 +2092,18 @@ schematic = (function() {
else
return
y
;
}
Component
.
prototype
.
moveTo
=
function
(
c
,
x
,
y
)
{
var
nx
=
this
.
transform_x
(
x
,
y
)
+
this
.
x
;
var
ny
=
this
.
transform_y
(
x
,
y
)
+
this
.
y
;
this
.
sch
.
moveTo
(
c
,
nx
,
ny
);
}
Component
.
prototype
.
lineTo
=
function
(
c
,
x
,
y
)
{
var
nx
=
this
.
transform_x
(
x
,
y
)
+
this
.
x
;
var
ny
=
this
.
transform_y
(
x
,
y
)
+
this
.
y
;
this
.
sch
.
lineTo
(
c
,
nx
,
ny
);
}
Component
.
prototype
.
draw_line
=
function
(
c
,
x1
,
y1
,
x2
,
y2
)
{
c
.
strokeStyle
=
this
.
selected
?
selected_style
:
normal_style
;
var
nx1
=
this
.
transform_x
(
x1
,
y1
)
+
this
.
x
;
...
...
@@ -1775,39 +2213,19 @@ schematic = (function() {
Component
.
prototype
.
edit_properties
=
function
(
x
,
y
)
{
if
(
inside
(
this
.
bbox
,
x
,
y
))
{
var
content
=
document
.
createElement
(
'table'
);
content
.
style
.
marginBotton
=
'5px'
;
content
.
fields
=
[];
// add an <input> field for each property
for
(
var
i
in
this
.
properties
)
{
var
label
=
document
.
createTextNode
(
i
+
': '
);
var
field
=
document
.
createElement
(
'input'
);
field
.
type
=
'text'
;
var
pvalue
=
this
.
properties
[
i
];
field
.
value
=
pvalue
?
pvalue
:
''
;
field
.
size
=
10
;
content
.
fields
.
push
([
i
,
field
]);
var
col1
=
document
.
createElement
(
'td'
);
col1
.
appendChild
(
label
);
var
col2
=
document
.
createElement
(
'td'
);
col2
.
appendChild
(
field
);
var
row
=
document
.
createElement
(
'tr'
);
row
.
appendChild
(
col1
);
row
.
appendChild
(
col2
);
row
.
style
.
verticalAlign
=
'center'
;
content
.
appendChild
(
row
);
}
// make an <input> widget for each property
var
fields
=
new
Array
();
for
(
var
i
in
this
.
properties
)
fields
[
i
]
=
build_input
(
'text'
,
10
,
this
.
properties
[
i
]);
var
component
=
this
;
// capture in closure below
var
content
=
build_table
(
fields
);
content
.
fields
=
fields
;
content
.
component
=
this
;
this
.
sch
.
dialog
(
'Edit Properties'
,
content
,
function
(
content
)
{
var
fields
=
content
.
fields
;
for
(
var
i
=
fields
.
length
-
1
;
i
>=
0
;
i
--
)
component
.
properties
[
fields
[
i
][
0
]]
=
fields
[
i
][
1
].
value
;
component
.
sch
.
redraw_background
();
for
(
var
i
in
content
.
fields
)
content
.
component
.
properties
[
i
]
=
content
.
fields
[
i
].
value
;
content
.
component
.
sch
.
redraw_background
();
});
return
true
;
}
else
return
false
;
...
...
@@ -1912,8 +2330,10 @@ schematic = (function() {
var
label
=
v
.
toFixed
(
2
)
+
'V'
;
// first draw some solid blocks in the background
this
.
parent
.
draw_text
(
c
,
'
\
u2588
\
u2588
\
u2588
\
u2588'
,
this
.
offset_x
,
this
.
offset_y
,
4
,
annotation_size
,
background_style
);
c
.
globalAlpha
=
0.85
;
this
.
parent
.
draw_text
(
c
,
'
\
u2588
\
u2588
\
u2588'
,
this
.
offset_x
,
this
.
offset_y
,
4
,
annotation_size
,
element_style
);
c
.
globalAlpha
=
1.0
;
// display the node voltage at this connection point
this
.
parent
.
draw_text
(
c
,
label
,
this
.
offset_x
,
this
.
offset_y
,
...
...
@@ -1934,7 +2354,7 @@ schematic = (function() {
function
Wire
(
x1
,
y1
,
x2
,
y2
)
{
// arbitrarily call x1,y1 the origin
Component
.
call
(
this
,
x1
,
y1
,
0
);
Component
.
call
(
this
,
'w'
,
x1
,
y1
,
0
);
this
.
dx
=
x2
-
x1
;
this
.
dy
=
y2
-
y1
;
this
.
add_connection
(
0
,
0
);
...
...
@@ -2045,11 +2465,10 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
function
Ground
(
x
,
y
,
rotation
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
Component
.
call
(
this
,
'g'
,
x
,
y
,
rotation
);
this
.
add_connection
(
0
,
0
);
this
.
bounding_box
=
[
-
6
,
0
,
6
,
8
];
this
.
update_coords
();
this
.
type
=
'g'
;
}
Ground
.
prototype
=
new
Component
();
Ground
.
prototype
.
constructor
=
Ground
;
...
...
@@ -2075,19 +2494,95 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
//
// Scope Probe
//
////////////////////////////////////////////////////////////////////////////////
probe_colors
=
[
'red'
,
'green'
,
'blue'
,
'cyan'
,
'magenta'
,
'black'
];
probe_colors_rgb
=
{
'red'
:
'rgb(255,64,64)'
,
'green'
:
'rgb(64,255,64)'
,
'blue'
:
'rgb(64,64,255)'
,
'cyan'
:
'rgb(64,255,255)'
,
'magenta'
:
'rgb(255,64,255)'
,
'black'
:
'rgb(0,0,0)'
,
};
function
Probe
(
x
,
y
,
rotation
,
color
)
{
Component
.
call
(
this
,
's'
,
x
,
y
,
rotation
);
this
.
add_connection
(
0
,
0
);
this
.
properties
[
'color'
]
=
color
?
color
:
'cyan'
;
this
.
bounding_box
=
[
0
,
0
,
27
,
-
21
];
this
.
update_coords
();
}
Probe
.
prototype
=
new
Component
();
Probe
.
prototype
.
constructor
=
Probe
;
Probe
.
prototype
.
toString
=
function
()
{
return
'<Probe ('
+
this
.
x
+
','
+
this
.
y
+
')>'
;
}
Probe
.
prototype
.
draw
=
function
(
c
)
{
// draw outline
this
.
draw_line
(
c
,
0
,
0
,
4
,
-
4
);
this
.
draw_line
(
c
,
2
,
-
6
,
6
,
-
2
);
this
.
draw_line
(
c
,
2
,
-
6
,
17
,
-
21
);
this
.
draw_line
(
c
,
6
,
-
2
,
21
,
-
17
);
this
.
draw_line
(
c
,
17
,
-
21
,
21
,
-
17
);
this
.
draw_arc
(
c
,
19
,
-
11
,
8
,
3
*
Math
.
PI
/
2
,
0
);
// fill body with plot color
c
.
fillStyle
=
probe_colors_rgb
[
this
.
properties
[
'color'
]];
c
.
beginPath
();
this
.
moveTo
(
c
,
2
,
-
6
)
this
.
lineTo
(
c
,
6
,
-
2
);
this
.
lineTo
(
c
,
21
,
-
17
);
this
.
lineTo
(
c
,
17
,
-
21
);
this
.
lineTo
(
c
,
2
,
-
6
);
c
.
fill
();
}
Probe
.
prototype
.
clone
=
function
(
x
,
y
)
{
return
new
Probe
(
x
,
y
,
this
.
rotation
,
this
.
properties
[
'color'
]);
}
Probe
.
prototype
.
edit_properties
=
function
(
x
,
y
)
{
if
(
inside
(
this
.
bbox
,
x
,
y
))
{
var
fields
=
new
Array
();
fields
[
'Plot color'
]
=
build_select
(
probe_colors
,
this
.
properties
[
'color'
]);
var
content
=
build_table
(
fields
);
content
.
fields
=
fields
;
content
.
component
=
this
;
this
.
sch
.
dialog
(
'Edit Properties'
,
content
,
function
(
content
)
{
var
color_choice
=
content
.
fields
[
'Plot color'
];
content
.
component
.
properties
[
'color'
]
=
probe_colors
[
color_choice
.
selectedIndex
];
content
.
component
.
sch
.
redraw_background
();
});
return
true
;
}
else
return
false
;
}
// return [color, node_label] for this probe
Probe
.
prototype
.
probe_info
=
function
()
{
return
[
this
.
properties
[
'color'
],
this
.
connections
[
0
].
label
];
}
////////////////////////////////////////////////////////////////////////////////
//
// Resistor
//
////////////////////////////////////////////////////////////////////////////////
function
Resistor
(
x
,
y
,
rotation
,
name
,
r
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
Component
.
call
(
this
,
'r'
,
x
,
y
,
rotation
);
this
.
properties
[
'name'
]
=
name
;
this
.
properties
[
'r'
]
=
r
?
r
:
'1'
;
this
.
add_connection
(
0
,
0
);
this
.
add_connection
(
0
,
48
);
this
.
bounding_box
=
[
-
4
,
0
,
4
,
48
];
this
.
update_coords
();
this
.
type
=
'r'
;
}
Resistor
.
prototype
=
new
Component
();
Resistor
.
prototype
.
constructor
=
Resistor
;
...
...
@@ -2123,14 +2618,13 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
function
Capacitor
(
x
,
y
,
rotation
,
name
,
c
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
Component
.
call
(
this
,
'c'
,
x
,
y
,
rotation
);
this
.
properties
[
'name'
]
=
name
;
this
.
properties
[
'c'
]
=
c
?
c
:
'1p'
;
this
.
add_connection
(
0
,
0
);
this
.
add_connection
(
0
,
48
);
this
.
bounding_box
=
[
-
8
,
0
,
8
,
48
];
this
.
update_coords
();
this
.
type
=
'c'
;
}
Capacitor
.
prototype
=
new
Component
();
Capacitor
.
prototype
.
constructor
=
Capacitor
;
...
...
@@ -2161,14 +2655,13 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
function
Inductor
(
x
,
y
,
rotation
,
name
,
l
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
Component
.
call
(
this
,
'l'
,
x
,
y
,
rotation
);
this
.
properties
[
'name'
]
=
name
;
this
.
properties
[
'l'
]
=
l
?
l
:
'1n'
;
this
.
add_connection
(
0
,
0
);
this
.
add_connection
(
0
,
48
);
this
.
bounding_box
=
[
-
4
,
0
,
5
,
48
];
this
.
update_coords
();
this
.
type
=
'l'
;
}
Inductor
.
prototype
=
new
Component
();
Inductor
.
prototype
.
constructor
=
Inductor
;
...
...
@@ -2201,13 +2694,12 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
function
Diode
(
x
,
y
,
rotation
,
name
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
Component
.
call
(
this
,
'd'
,
x
,
y
,
rotation
);
this
.
properties
[
'name'
]
=
name
;
this
.
add_connection
(
0
,
0
);
// anode
this
.
add_connection
(
0
,
48
);
// cathode
this
.
bounding_box
=
[
-
8
,
0
,
8
,
48
];
this
.
update_coords
();
this
.
type
=
'd'
;
}
Diode
.
prototype
=
new
Component
();
Diode
.
prototype
.
constructor
=
Diode
;
...
...
@@ -2239,7 +2731,7 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
function
NFet
(
x
,
y
,
rotation
,
name
,
sw
,
sl
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
Component
.
call
(
this
,
'n'
,
x
,
y
,
rotation
);
this
.
properties
[
'name'
]
=
name
;
this
.
properties
[
'scaled width'
]
=
sw
?
sw
:
'2'
;
this
.
properties
[
'scaled length'
]
=
sl
?
sl
:
'1'
;
...
...
@@ -2248,7 +2740,6 @@ schematic = (function() {
this
.
add_connection
(
-
24
,
24
);
// gate
this
.
bounding_box
=
[
-
24
,
0
,
8
,
48
];
this
.
update_coords
();
this
.
type
=
'n'
;
}
NFet
.
prototype
=
new
Component
();
NFet
.
prototype
.
constructor
=
NFet
;
...
...
@@ -2287,7 +2778,7 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
function
PFet
(
x
,
y
,
rotation
,
name
,
sw
,
sl
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
Component
.
call
(
this
,
'p'
,
x
,
y
,
rotation
);
this
.
properties
[
'name'
]
=
name
;
this
.
properties
[
'scaled width'
]
=
sw
?
sw
:
'2'
;
this
.
properties
[
'scaled length'
]
=
sl
?
sl
:
'1'
;
...
...
@@ -2296,7 +2787,6 @@ schematic = (function() {
this
.
add_connection
(
-
24
,
24
);
// gate
this
.
bounding_box
=
[
-
24
,
0
,
8
,
48
];
this
.
update_coords
();
this
.
type
=
'p'
;
}
PFet
.
prototype
=
new
Component
();
PFet
.
prototype
.
constructor
=
PFet
;
...
...
@@ -2337,14 +2827,13 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
function
OpAmp
(
x
,
y
,
rotation
,
name
,
sw
,
sl
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
Component
.
call
(
this
,
'o'
,
x
,
y
,
rotation
);
this
.
properties
[
'name'
]
=
name
;
this
.
add_connection
(
0
,
0
);
// +
this
.
add_connection
(
0
,
16
);
// -
this
.
add_connection
(
48
,
8
);
// output
this
.
bounding_box
=
[
0
,
-
8
,
48
,
24
];
this
.
update_coords
();
this
.
type
=
'o'
;
}
OpAmp
.
prototype
=
new
Component
();
OpAmp
.
prototype
.
constructor
=
OpAmp
;
...
...
@@ -2382,8 +2871,7 @@ schematic = (function() {
////////////////////////////////////////////////////////////////////////////////
function
Source
(
x
,
y
,
rotation
,
name
,
type
,
value
)
{
Component
.
call
(
this
,
x
,
y
,
rotation
);
this
.
type
=
type
;
Component
.
call
(
this
,
type
,
x
,
y
,
rotation
);
this
.
properties
[
'name'
]
=
name
;
this
.
properties
[
'value'
]
=
value
?
value
:
'1'
;
this
.
add_connection
(
0
,
0
);
...
...
@@ -2404,10 +2892,12 @@ schematic = (function() {
this
.
draw_line
(
c
,
0
,
36
,
0
,
48
);
if
(
this
.
type
==
'v'
)
{
// voltage source
this
.
draw_text
(
c
,
'+'
,
0
,
12
,
1
,
property_size
);
this
.
draw_text
(
c
,
'
\
u2013'
,
0
,
36
,
7
,
property_size
);
// minus sign
// draw + and -
this
.
draw_line
(
c
,
8
,
5
,
8
,
11
);
this
.
draw_line
(
c
,
5
,
8
,
11
,
8
);
this
.
draw_line
(
c
,
5
,
40
,
11
,
40
);
//
this.draw_line(c,8,5,8,11);
//
this.draw_line(c,5,8,11,8);
//
this.draw_line(c,5,40,11,40);
// draw V
this
.
draw_line
(
c
,
-
3
,
20
,
0
,
28
);
this
.
draw_line
(
c
,
3
,
20
,
0
,
28
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment