Commit 87191432 by Piotr Mitros

Schematic with center tag from cjt

parent d54ab750
......@@ -4,12 +4,30 @@
//
//////////////////////////////////////////////////////////////////////////////
// Chris Terman, Dec. 2011
// Copyright (C) 2011 Massachusetts Institute of Technology
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// create a circuit for simulation using "new cktsim.Circuit()"
// for modified nodal analysis (MNA) stamps see
// http://books.google.com/books?id=qhHsSlazGrQC&pg=PA44&lpg=PA44&dq=MNA+stamp+inductor&source=bl&ots=ThMq-FmhLo&sig=cTP1ld_fhIJbGPSBXPDbh3Xappk&hl=en&sa=X&ei=6wb-ToecFMHj0QH61-Fs&ved=0CFcQ6AEwAw#v=onepage&q=MNA%20stamp%20inductor&f=false
// http://www.analog-electronics.eu/analog-electronics/modified-nodal-analysis/modified-nodal-analysis.xhtml
cktsim = (function() {
......@@ -23,6 +41,15 @@ cktsim = (function() {
T_VOLTAGE = 0;
T_CURRENT = 1;
v_abstol = 1e-6; // criterion for absolute convergence (voltage)
i_abstol = 1e-12; // criterion for absolute convergence (current)
min_time_step = 1e-18; // smallest possible time step
max_iterations = 50; // max iterations before giving up
increase_limit = 4; // if we converge in this many iterations, increase time step
time_step_increase_factor = 2.0;
time_step_decrease_factor = 0.3;
reltol = 0.001; // convergence criterion relative to max observed value
function Circuit() {
this.node_map = new Array();
this.ntypes = [];
......@@ -34,11 +61,6 @@ cktsim = (function() {
this.finalized = false;
this.node_index = -1;
// for backward Euler: coeff0 = 1/timestep, coeff1 = 0
// for trapezoidal: coeff0 = 2/timestep, coeff1 = 1
this.coeff0 = undefined;
this.coeff1 = undefined;
}
// index of ground node
......@@ -67,10 +89,22 @@ cktsim = (function() {
// set up augmented matrix and various temp vectors
this.matrix = new Array(this.N);
for (var i = this.N - 1; i >= 0; --i)
this.soln_max = new Array(this.N); // max abs value seen for each unknown
this.rtol = new Array(this.N); // soln_max * reltol
this.abstol = new Array(this.N);
this.solution = new Array(this.N);
for (var i = this.N - 1; i >= 0; --i) {
this.matrix[i] = new Array(this.N + 1);
this.swap = new Array(this.N); // keep track of row swaps during pivoting
this.soln = new Array(this.N); // hold swapped solution
this.soln_max[i] = 0.0;
this.rtol[i] = 0.0;
this.abstol[i] = this.ntypes[i] == T_VOLTAGE ? v_abstol : i_abstol;
this.solution[i] = 0.0;
}
// for backward Euler: coeff0 = 1/timestep, coeff1 = 0
// for trapezoidal: coeff0 = 2/timestep, coeff1 = 1
this.coeff0 = undefined;
this.coeff1 = undefined;
}
}
......@@ -84,8 +118,8 @@ cktsim = (function() {
var component = netlist[i];
var type = component[0];
// ignore wires, ground connections and view info
if (type == 'view' || type == 'w' || type == 'g') continue;
// ignore wires, ground connections, scope probes and view info
if (type == 'view' || type == 'w' || type == 'g' || type == 's') continue;
var properties = component[2];
var name = properties['name'];
......@@ -121,27 +155,127 @@ cktsim = (function() {
}
}
// if converges: updates this.solution, this.soln_max, returns iter count
// otherwise: return undefined and set this.problem_node
// The argument should be a function that sets up the linear system.
Circuit.prototype.find_solution = function(load) {
var soln = this.solution;
var old_soln,temp,converged;
// iteratively solve until values convere or iteration limit exceeded
for (var iter = 0; iter < max_iterations; i++) {
// set up equations
this.initialize_linear_system();
load(this);
// solve for node voltages and branch currents
old_soln = soln;
soln = solve_linear_system(this.matrix);
// check convergence: abs(new-old) <= abstol + reltol*max;
converged = true;
for (var i = this.N - 1; i >= 0; --i) {
temp = Math.abs(soln[i] - old_soln);
if (temp > this.abstol[i] + this.rtol[i]) {
converged = false;
this.problem_node = i;
break;
}
}
if (!converged) continue;
// other convergence checks here?
// update solution and maximum
this.solution = soln;
for (var i = this.N - 1; i >= 0; --i) {
temp = Math.abs(soln[i]);
if (temp > this.soln_max[i]) {
this.soln_max[i] = temp;
this.rtol[i] = temp * reltol;
}
}
return iter+1;
}
// too many iterations
return undefined;
}
// DC analysis
Circuit.prototype.dc = function() {
this.finalize();
// set up equations
this.initialize_linear_system();
for (var i = this.devices.length - 1; i >= 0; --i)
this.devices[i].load_dc(this);
// this function calls load_dc for all devices
function load_dc(ckt) {
for (var i = ckt.devices.length - 1; i >= 0; --i)
ckt.devices[i].load_dc(ckt);
}
// find the operating point
var iterations = this.find_solution(load_dc);
// solve for operating point
var x = solve_linear_system(this.matrix);
if (typeof iterations == 'undefined')
return 'Node '+this.node_map[this.problem_node]+' did not converge';
// create solution dictionary
var result = new Array();
for (var name in this.node_map) {
var index = this.node_map[name];
result[name] = (index == -1) ? 0 : x[index];
result[name] = (index == -1) ? 0 : this.solution[index];
}
return result;
}
// AC analysis: npts/decade for freqs in range [fstart,fstop]
// result['frequencies'] = vector of log10(sample freqs)
// result['xxx'] = vector of dB(response for node xxx)
Circuit.prototype.ac = function(npts,fstart,fstop) {
this.finalize();
// this function calls load_ac for all devices
function load_ac(ckt) {
for (var i = ckt.devices.length - 1; i >= 0; --i)
ckt.devices[i].load_ac(ckt);
}
// build array to hold list of results for each node
// last entry is for frequency values
var response = new Array(this.N + 1);
for (var i = this.N; i >= 0; --i) response[i] = new Array();
// multiplicative frequency increase between freq points
var delta_f = Math.exp(Math.LN10/npts);
var f = fstart;
fstop *= 1.0001; // capture that last time point!
while (f <= fstop) {
this.omega = 2 * Math.PI * f;
// find the operating point
var iterations = this.find_solution(load_ac);
if (typeof iterations == 'undefined')
return 'Node '+this.node_map[this.problem_node]+' did not converge';
else {
response[this.N].push(f);
for (var i = this.N - 1; i >= 0; --i)
response[i].push(this.solution[i]);
}
f *= delta_f; // increment frequency
}
// create solution dictionary
var result = new Array();
for (var name in this.node_map) {
var index = this.node_map[name];
result[name] = (index == -1) ? 0 : response[index];
}
result['frequencies'] = response[this.N];
return result;
}
Circuit.prototype.r = function(n1,n2,v,name) {
// try to convert string value into numeric value, barf if we can't
if ((typeof v) == 'string') {
......@@ -488,6 +622,8 @@ cktsim = (function() {
return result;
}
Circuit.prototype.parse_number = parse_number; // make it easy to call from outside
///////////////////////////////////////////////////////////////////////////////
//
// Sources
......@@ -650,19 +786,23 @@ cktsim = (function() {
VSource.prototype.construction = VSource;
// load linear system equations for dc analysis
VSource.prototype.load_dc = function(ckt,soln) {
VSource.prototype.load_dc = function(ckt) {
// MNA stamp for independent voltage source
ckt.add_to_A(this.branch,this.npos,1.0);
ckt.add_to_A(this.branch,this.nneg,-1.0);
ckt.add_to_A(this.npos,this.branch,1.0);
ckt.add_to_A(this.nneg,this.branch,-1.0);
ckt.add_to_b(this.branch,this.src.value(ckt.time));
ckt.add_to_b(this.branch,this.src.dc);
}
// load linear system equations for tran analysis (just like DC)
VSource.prototype.load_tran = function(ckt,soln) {
this.load_dc(ckt);
// MNA stamp for independent voltage source
ckt.add_to_A(this.branch,this.npos,1.0);
ckt.add_to_A(this.branch,this.nneg,-1.0);
ckt.add_to_A(this.npos,this.branch,1.0);
ckt.add_to_A(this.nneg,this.branch,-1.0);
ckt.add_to_b(this.branch,this.src.value(ckt.time));
}
// return time of next breakpoint for the device
......@@ -671,12 +811,8 @@ cktsim = (function() {
}
// small signal model: short circuit
VSource.prototype.load_ac = function() {
// use branch row in matrix to set following constraint on system:
// v_pos - v_neg = 0V
ckt.add_to_A(this.branch,this.npos,1.0);
ckt.add_to_A(this.branch,this.nneg,-1.0);
// ckt.add_to_b(this.branch,0); // adding 0 isn't necessary!
VSource.prototype.load_ac = function(ckt) {
this.load_dc(ckt);
}
function ISource(npos,nneg,v) {
......@@ -691,7 +827,7 @@ cktsim = (function() {
// load linear system equations for dc analysis
ISource.prototype.load_dc = function(ckt) {
var i = this.src.value(ckt.time);
var i = this.src.dc;
// MNA stamp for independent current source
ckt.add_to_b(this.npos,-i); // current flow into npos
......@@ -700,7 +836,11 @@ cktsim = (function() {
// load linear system equations for tran analysis (just like DC)
ISource.prototype.load_tran = function(ckt,soln) {
this.load_dc(ckt);
var i = this.src.value(ckt.time);
// MNA stamp for independent current source
ckt.add_to_b(this.npos,-i); // current flow into npos
ckt.add_to_b(this.nneg,i); // and out of nneg
}
// return time of next breakpoint for the device
......@@ -709,7 +849,8 @@ cktsim = (function() {
}
// small signal model: open circuit
ISource.prototype.load_ac = function() {
ISource.prototype.load_ac = function(ckt) {
this.load_dc(ckt);
}
///////////////////////////////////////////////////////////////////////////////
......
......@@ -4,11 +4,29 @@
//
////////////////////////////////////////////////////////////////////////////////
// Chris Terman, Nov. 2011
// Copyright (C) 2011 Massachusetts Institute of Technology
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// add schematics to a document with
//
// <input type="hidden" class="schematic" name="unique_form_id" value="...schematic/netlist info..." .../>
// <input type="hidden" class="schematic" name="unique_form_id" value="JSON netlist..." .../>
//
// other attributes you can add to the input tag:
// width -- width in pixels of diagram
......@@ -27,14 +45,8 @@
// need a netlist? just use the part's type, properites and connections
// TO DO:
// - draggable overlay window base class (dialogs, scope, ...)
// - wire labels?
// - devices: diode, nfet, pfet, opamp, scope probe
// - icons for test equipment? (scope, sig gen, counter, ...)
// - zoom/scroll canvas
// - freeze_diagram, freeze_properties attributes (freeze certain components/properties?)
// - rotate multiple objects around their center of mass
// - rubber band wires when moving components
......@@ -100,11 +112,7 @@ schematic = (function() {
// setup a schematic by populating the <div> with the appropriate children
function Schematic(input) {
this.div = document.createElement('div');
// set up div so we can position elements inside of it
this.div.style.position = 'relative';
this.div.style.cursor = 'default';
// set up diagram viewing parameters
this.grid = 8;
this.scale = 2;
this.origin_x = input.getAttribute("origin_x");
......@@ -125,6 +133,15 @@ schematic = (function() {
parts = [];
} else parts = parts.split(',');
// now add the parts to the parts bin
this.parts_bin = [];
for (var i = 0; i < parts.length; i++) {
var part = new Part(this);
var pm = parts_map[parts[i]];
part.set_component(new pm[0](0,0,0),pm[1]);
this.parts_bin.push(part);
}
// use user-supplied list of analyses, otherwise provide them all
// analyses="" means no analyses
var analyses = input.getAttribute('analyses');
......@@ -135,46 +152,6 @@ schematic = (function() {
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;
this.background.style.borderStyle = 'solid';
this.background.style.borderWidth = '2px';
this.status_div = document.createElement('div');
this.status_div.style.position = 'absolute';
this.status_div.style.padding = '2px';
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);
this.canvas.addEventListener('mousedown',schematic_mouse_down,false);
this.canvas.addEventListener('mouseup',schematic_mouse_up,false);
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 = [];
......@@ -206,6 +183,52 @@ schematic = (function() {
}
}
// set up diagram canvas
this.canvas = document.createElement('canvas');
this.width = input.getAttribute('width');
this.width = parseInt(this.width == undefined ? '400' : this.width);
this.canvas.width = this.width;
this.height = input.getAttribute('height');
this.height = parseInt(this.height == undefined ? '300' : this.height);
this.canvas.height = this.height;
// repaint simply draws this buffer and then adds selected elements on top
this.bg_image = document.createElement('canvas');
this.bg_image.width = this.width;
this.bg_image.height = this.height;
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);
this.canvas.addEventListener('mousedown',schematic_mouse_down,false);
this.canvas.addEventListener('mouseup',schematic_mouse_up,false);
this.canvas.addEventListener('dblclick',schematic_double_click,false);
this.canvas.addEventListener('keydown',schematic_key_down,false);
this.canvas.addEventListener('keyup',schematic_key_up,false);
}
// set up message area
if (!this.diagram_only) {
this.status_div = document.createElement('div');
this.status = document.createTextNode('');
this.status_div.appendChild(this.status);
this.status_div.style.height = status_height + 'px';
} else this.status_div = undefined;
this.connection_points = new Array(); // location string => list of cp's
this.components = [];
this.dragging = false;
this.drawCursor = false;
this.cursor_x = 0;
......@@ -222,148 +245,78 @@ schematic = (function() {
this.altKey = false;
this.cmdKey = false;
// repaint simply draws this buffer and then adds selected elements on top
this.bg_image = document.createElement('canvas');
// make sure other code can find us!
input.schematic = this;
this.input = input;
// now add the parts to the parts bin
var parts_left = this.width + 3 + background_margin;
var parts_top = background_margin;
this.parts_bin = [];
for (var i = 0; i < parts.length; i++) {
var part = new Part(this);
var pm = parts_map[parts[i]];
part.set_component(new pm[0](0,0,0),pm[1]);
this.parts_bin.push(part);
// set up DOM -- use nested tables to do the layout
var table,tr,td;
table = document.createElement('table');
if (!this.diagram_only) {
table.style.borderStyle = 'solid';
table.style.borderWidth = '2px';
table.style.padding = '5px';
table.style.backgroundColor = background_style;
}
// add all elements to the DOM
if (!this.diagram_only) {
this.div.appendChild(this.background);
for (var i = 0; i < this.toolbar.length; i++) {
// add tools to DOM
if (this.toolbar.length > 0) {
tr = document.createElement('tr');
table.appendChild(tr);
td = document.createElement('td');
td.colspan = 2;
td.vAlign = 'baseline';
tr.appendChild(td);
for (var i = 0; i < this.toolbar.length; ++i) {
var tool = this.toolbar[i];
if (tool != null) this.div.appendChild(tool);
if (tool != null) td.appendChild(tool);
}
}
// add canvas and parts bin to DOM
tr = document.createElement('tr');
tr.vAlign = 'top';
table.appendChild(tr);
td = document.createElement('td');
tr.appendChild(td);
td.appendChild(this.canvas);
td = document.createElement('td');
tr.appendChild(td);
var parts_table = document.createElement('table');
td.appendChild(parts_table);
// fill in parts_table here!!!
var parts_per_column = Math.floor(this.height / part_h);
for (var i = 0; i < parts_per_column; ++i) {
tr = document.createElement('tr');
parts_table.appendChild(tr);
for (var j = i; j < this.parts_bin.length; j += parts_per_column) {
td = document.createElement('td');
tr.appendChild(td);
td.appendChild(this.parts_bin[j].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!
input.schematic = this;
this.input = input;
if (this.status_div != undefined) {
tr = document.createElement('tr');
table.appendChild(tr);
td = document.createElement('td');
tr.appendChild(td);
td.colspan = 2;
td.appendChild(this.status_div);
}
// set locations of all the elements in the editor
var w = parseInt(input.getAttribute('width'));
var h = parseInt(input.getAttribute('height'));
this.set_locations(w,h);
// add to dom
this.input.parentNode.insertBefore(table,this.input.nextSibling);
// process initial contents of diagram
this.load_schematic(this.input.value);
}
background_margin = 5;
part_w = 42; // size of a parts bin compartment
part_h = 42;
status_height = 18;
// w,h are the dimensions of the canvas, everyone else is positioned accordingly
Schematic.prototype.set_locations = function(w,h) {
// 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,top;
// start with tool bar
left = 2*background_margin; // space to the left
top = background_margin;
var max_height = 0;
if (this.toolbar.length > 0) {
tool_left = left;
for (var i = 0; i < this.toolbar.length; i++) {
var tool = this.toolbar[i];
if (tool == null) { // spacer
tool_left += 8;
continue;
}
tool.style.left = tool_left + 'px';
tool.style.top = top + 'px';
tool_left += tool.offsetWidth + 2; // width + padding + border + gap
max_height = Math.max(max_height,tool.offsetHeight);
}
top += max_height + 5; // height + padding + border + gap;
}
// configure canvas
this.canvas.style.left = left + 'px';
this.canvas.style.top = top + 'px';
this.canvas.width = w;
this.canvas.height = h;
this.redraw_background(); // redraw diagram
// configure status bar
this.status_div.style.left = left + 'px';
this.status_div.style.top = this.canvas.offsetTop + this.canvas.offsetHeight + 3 + 'px';
this.status_div.style.width = (w - 4) + 'px'; // subtract interior padding
this.status_div.style.height = status_height + 'px';
// configure parts bin
var total_w = this.canvas.offsetLeft + this.canvas.offsetWidth;
var parts_left = total_w + 5;
var parts_top = top;
var parts_h_limit = this.canvas.offsetTop + this.canvas.offsetHeight;
for (var i = 0; i < this.parts_bin.length; i++) {
var part = this.parts_bin[i];
part.set_location(parts_left,parts_top);
total_w = part.right();
parts_top = part.bottom() + 2;
if (parts_top + part_h > parts_h_limit) {
parts_left = total_w + 2;
parts_top = top;
}
}
// configure background
var total_h = this.status_div.offsetTop + this.status_div.offsetHeight + background_margin;
total_w += background_margin;
this.background.height = total_h;
this.background.width = total_w;
/* enable when there's support for resizing schematic
// redraw thumb
var c = this.background.getContext('2d');
c.clearRect(0,0,w,h);
c.strokeStyle = thumb_style;
c.lineWidth = 1;
c.beginPath();
w = total_w - 1;
h = total_h - 1;
c.moveTo(w,h-4); c.lineTo(w-4,h);
c.moveTo(w,h-8); c.lineTo(w-8,h);
c.moveTo(w,h-12); c.lineTo(w-12,h);
c.stroke();
*/
}
Schematic.prototype.add_component = function(new_c) {
this.components.push(new_c);
......@@ -570,10 +523,10 @@ schematic = (function() {
part.add(this)
}
}
// see what we've got!
this.redraw_background();
}
// see what we've got!
this.redraw_background();
}
// label all the nodes in the circuit
......@@ -764,8 +717,6 @@ schematic = (function() {
// Also redraws dynamic portion.
Schematic.prototype.redraw_background = function() {
var c = this.bg_image.getContext('2d');
var w = this.bg_image.width;
var h = this.bg_imageheight;
c.lineCap = 'round';
......@@ -776,10 +727,10 @@ schematic = (function() {
// grid
c.strokeStyle = grid_style;
var first_x = this.min_x;
var last_x = this.max_x;
var first_y = this.min_y;
var last_y = this.max_y;
var first_x = 0;
var last_x = this.width/this.scale;
var first_y = 0;
var last_y = this.height/this.scale;
for (var i = first_x; i < last_x; i += this.grid)
this.draw_line(c,i,first_y,i,last_y,0.1);
for (var i = first_y; i < last_y; i += this.grid)
......@@ -903,22 +854,27 @@ schematic = (function() {
c.fillText(text,(x - this.origin_x) * this.scale,(y - this.origin_y) * this.scale);
}
HTMLCanvasElement.prototype.totalOffset = function(){
}
// add method to canvas to compute relative coords for event
HTMLCanvasElement.prototype.relMouseCoords = function(event){
// run up the DOM tree to figure out coords for top,left of canvas
var totalOffsetX = 0;
var totalOffsetY = 0;
var canvasY = 0;
var currentElement = this;
do {
totalOffsetX += currentElement.offsetLeft;
totalOffsetY += currentElement.offsetTop;
}
while(currentElement = currentElement.offsetParent);
while (currentElement = currentElement.offsetParent);
// now compute relative position of click within the canvas
this.mouse_x = event.pageX - totalOffsetX;
this.mouse_y = event.pageY - totalOffsetY;
this.page_x = event.pageX;
this.page_y = event.pageY;
}
///////////////////////////////////////////////////////////////////////////////
......@@ -1365,8 +1321,8 @@ schematic = (function() {
content.win = win; // so content can contact us
// compute location in top-level div
win.left = this.canvas.mouse_x + this.canvas.offsetLeft;
win.top = this.canvas.mouse_y + this.canvas.offsetTop;
win.left = this.canvas.page_x;
win.top = this.canvas.page_y;
// add to DOM
win.style.background = 'white';
......@@ -1375,7 +1331,8 @@ schematic = (function() {
win.style.left = win.left + 'px';
win.style.top = win.top + 'px';
win.style.border = '2px solid';
this.div.appendChild(win);
this.input.parentNode.insertBefore(win,this.input.nextSibling);
}
// close the window
......@@ -1458,7 +1415,7 @@ schematic = (function() {
tool.style.borderWidth = '1px';
tool.style.borderStyle = 'solid';
tool.style.borderColor = background_style;
tool.style.position = 'absolute';
//tool.style.position = 'absolute';
tool.style.padding = '2px';
// set up event processing
......@@ -1783,7 +1740,7 @@ schematic = (function() {
this.canvas.style.borderStyle = 'solid';
this.canvas.style.borderWidth = '1px';
this.canvas.style.borderColor = background_style;
this.canvas.style.position = 'absolute';
//this.canvas.style.position = 'absolute';
this.canvas.style.cursor = 'default';
this.canvas.height = part_w;
this.canvas.width = part_h;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment