akiha-circuit
Version:
Draws electric circuit diagram by ASCII art
314 lines (290 loc) • 15.7 kB
JavaScript
/*
* akiha-circuit
*
* Copyright (c) 2019 Yuichiro MORIGUCHI
*
* This software is released under the MIT License.
* http://opensource.org/licenses/mit-license.php
**/
var common = require("./akiha-common.js");
var defaultOption = {
sideLength: 110,
marginX: 70,
marginY: 60,
stroke: "#000000",
fill: "white",
resistorLong: 50,
resistorShort: 14,
batteryGap: 6,
batteryLong: 20,
batteryShort: 10,
capacitorGap: 10,
capacitorLength: 16,
inductorLength: 40,
voltageACRadius: 10,
voltageACx: 6,
voltageACy: 8,
voltageACFill: "none",
jointRadius: 2,
fontFamily: "sans-serif",
fontSize: "10pt",
textMargin: 14,
polarityLength: 12,
polarityLengthMinor: 4
};
function createDrawer(xMaxNodes, yMaxNodes, svg, option) {
var me,
canvas,
sideLen,
opt = option ? common.extend(defaultOption, option) : defaultOption;
function getPoint(point) {
var rpoint = sideLen.getLength({ x: 0, y: 0 }, point),
result;
result = {
x: opt.marginX + rpoint.x * opt.sideLength,
y: opt.marginY + rpoint.y * opt.sideLength
};
return result;
}
function makeDrawing(length, drawX, drawY) {
return function(point1, point2, divide, serial) {
var pax = getPoint(point1).x,
pay = getPoint(point1).y,
pbx = getPoint(point2).x,
pby = getPoint(point2).y,
p1x = pax < pbx ? pax : pbx,
p1y = pay < pby ? pay : pby,
p2x = pax >= pbx ? pax : pbx,
p2y = pay >= pby ? pay : pby,
p3,
p4,
pl1,
pl2,
points = "";
if(pay === pby) {
if(pax < pbx) {
p3 = p1x + (p2x - p1x) * (divide) / serial;
p4 = p1x + (p2x - p1x) * (divide + 1) / serial;
} else {
p3 = p1x + (p2x - p1x) * (serial - divide - 1) / serial;
p4 = p1x + (p2x - p1x) * (serial - divide) / serial;
}
pl1 = p3 + (p4 - p3) / 2 - length / 2;
pl2 = p3 + (p4 - p3) / 2 + length / 2;
drawX(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4);
} else {
if(pay < pby) {
p3 = p1y + (p2y - p1y) * (divide) / serial;
p4 = p1y + (p2y - p1y) * (divide + 1) / serial;
} else {
p3 = p1y + (p2y - p1y) * (serial - divide - 1) / serial;
p4 = p1y + (p2y - p1y) * (serial - divide) / serial;
}
pl1 = p3 + (p4 - p3) / 2 - length / 2;
pl2 = p3 + (p4 - p3) / 2 + length / 2;
drawY(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4);
}
}
}
me = {
setSideLength: function(sideLength) {
var xLen,
yLen;
sideLen = sideLength;
xLen = sideLen.getLength({ x: 0, y: 0 }, { x: xMaxNodes - 1, y: 0 }).x;
yLen = sideLen.getLength({ x: 0, y: 0 }, { x: 0, y: yMaxNodes - 1 }).y;
canvas = svg.createCanvas(opt.marginX * 2 + xLen * opt.sideLength, opt.marginY * 2 + yLen * opt.sideLength);
},
drawLine: function(point1, point2) {
svg.addLine(canvas, getPoint(point1).x, getPoint(point1).y, getPoint(point2).x, getPoint(point2).y, opt.stroke);
},
drawJoint: function(point) {
svg.addCircle(canvas, getPoint(point).x, getPoint(point).y, opt.jointRadius, opt.stroke);
},
drawResistor: makeDrawing(
opt.resistorLong,
function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
var points = "";
points += "M " + pl1 + " " + (pay - opt.resistorShort / 2) + " ";
points += "L " + pl2 + " " + (pay - opt.resistorShort / 2) + " ";
points += "L " + pl2 + " " + (pay + opt.resistorShort / 2) + " ";
points += "L " + pl1 + " " + (pay + opt.resistorShort / 2) + " ";
points += "L " + pl1 + " " + (pay - opt.resistorShort / 2);
svg.addPath(canvas, points, opt.fill, opt.stroke);
svg.addLine(canvas, p3, pay, pl1, pay, opt.stroke);
svg.addLine(canvas, pl2, pay, p4, pay, opt.stroke);
svg.addText(canvas, point1.text, pl1, pay - opt.textMargin, opt);
if(point1.name) {
svg.addText(canvas, point1.name, pl1, pay - opt.textMargin * 2, opt);
}
}, function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
var points = "";
points += "M " + (pax - opt.resistorShort / 2) + " " + pl1 + " ";
points += "L " + (pax - opt.resistorShort / 2) + " " + pl2 + " ";
points += "L " + (pax + opt.resistorShort / 2) + " " + pl2 + " ";
points += "L " + (pax + opt.resistorShort / 2) + " " + pl1 + " ";
points += "L " + (pax - opt.resistorShort / 2) + " " + pl1;
svg.addPath(canvas, points, opt.fill, opt.stroke);
svg.addLine(canvas, pax, p3, pax, pl1, opt.stroke);
svg.addLine(canvas, pax, pl2, pax, p4, opt.stroke);
if(point1.name) {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2 + opt.textMargin / 2, opt);
svg.addText(canvas, point1.name, pax + opt.textMargin, p3 + (p4 - p3) / 2 - opt.textMargin / 2, opt);
} else {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2, opt);
}
}
),
drawBattery: makeDrawing(
opt.batteryGap,
function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
svg.addLine(canvas, p3, pay, pl1, pay, opt.stroke);
svg.addLine(canvas, pl2, pay, p4, pay, opt.stroke);
if((point1.voltage > 0 && p1x === pax) || (point1.voltage <= 0 && p1x !== pax)) {
svg.addLine(canvas, pl1, pay - opt.batteryLong / 2, pl1, pay + opt.batteryLong / 2, opt.stroke);
svg.addLine(canvas, pl2, pay - opt.batteryShort / 2, pl2, pay + opt.batteryShort / 2, opt.stroke);
} else {
svg.addLine(canvas, pl2, pay - opt.batteryLong / 2, pl2, pay + opt.batteryLong / 2, opt.stroke);
svg.addLine(canvas, pl1, pay - opt.batteryShort / 2, pl1, pay + opt.batteryShort / 2, opt.stroke);
}
svg.addText(canvas, point1.text, pl1, pay - opt.textMargin, opt);
if(point1.name) {
svg.addText(canvas, point1.name, pl1, pay - opt.textMargin * 2, opt);
}
}, function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
svg.addLine(canvas, pax, p3, pax, pl1, opt.stroke);
svg.addLine(canvas, pax, pl2, pax, p4, opt.stroke);
if((point1.voltage > 0 && p1y === pay) || (point1.voltage <= 0 && p1y !== pay)) {
svg.addLine(canvas, pax - opt.batteryLong / 2, pl1, pax + opt.batteryLong / 2, pl1, opt.stroke);
svg.addLine(canvas, pax - opt.batteryShort / 2, pl2, pax + opt.batteryShort / 2, pl2, opt.stroke);
} else {
svg.addLine(canvas, pax - opt.batteryLong / 2, pl2, pax + opt.batteryLong / 2, pl2, opt.stroke);
svg.addLine(canvas, pax - opt.batteryShort / 2, pl1, pax + opt.batteryShort / 2, pl1, opt.stroke);
}
if(point1.name) {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2 + opt.textMargin / 2, opt);
svg.addText(canvas, point1.name, pax + opt.textMargin, p3 + (p4 - p3) / 2 - opt.textMargin / 2, opt);
} else {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2, opt);
}
}
),
drawCapacitor: makeDrawing(
opt.capacitorGap,
function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
svg.addLine(canvas, p3, pay, pl1, pay, opt.stroke);
svg.addLine(canvas, pl2, pay, p4, pay, opt.stroke);
svg.addLine(canvas, pl1, pay - opt.capacitorLength / 2, pl1, pay + opt.capacitorLength / 2, opt.stroke);
svg.addLine(canvas, pl2, pay - opt.capacitorLength / 2, pl2, pay + opt.capacitorLength / 2, opt.stroke);
svg.addText(canvas, point1.text, pl1, pay - opt.textMargin, opt);
if(point1.name) {
svg.addText(canvas, point1.name, pl1, pay - opt.textMargin * 2, opt);
}
if(point1.polarity * (pax - pbx) > 0) {
svg.addText(canvas, "+", pl1 - opt.polarityLength, pay + opt.polarityLength, opt);
} else if(point1.polarity * (pax - pbx) < 0) {
svg.addText(canvas, "+", pl2 + opt.polarityLengthMinor, pay + opt.polarityLength, opt);
}
}, function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
svg.addLine(canvas, pax, p3, pax, pl1, opt.stroke);
svg.addLine(canvas, pax, pl2, pax, p4, opt.stroke);
svg.addLine(canvas, pax - opt.capacitorLength / 2, pl1, pax + opt.capacitorLength / 2, pl1, opt.stroke);
svg.addLine(canvas, pax - opt.capacitorLength / 2, pl2, pax + opt.capacitorLength / 2, pl2, opt.stroke);
if(point1.name) {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2 + opt.textMargin / 2, opt);
svg.addText(canvas, point1.name, pax + opt.textMargin, p3 + (p4 - p3) / 2 - opt.textMargin / 2, opt);
} else {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2, opt);
}
if(point1.polarity * (pay - pby) > 0) {
svg.addText(canvas, "+", pax - opt.polarityLength, pl1 - opt.polarityLengthMinor, opt);
} else if(point1.polarity * (pay - pby) < 0) {
svg.addText(canvas, "+", pax - opt.polarityLength, pl2 - opt.polarityLength, opt);
}
}
),
drawInductor: makeDrawing(
opt.inductorLength,
function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
function drawCoil1(num) {
var points = "";
points += "M " + (pl1 + opt.inductorLength * num / 4) + " " + pay + " ";
points += "a " + opt.inductorLength / 8 + " " + opt.inductorLength / 8 + " ";
points += "0 0 1 " + opt.inductorLength / 4 + " 0";
svg.addPath(canvas, points, opt.fill, opt.stroke);
}
svg.addLine(canvas, p3, pay, pl1, pay, opt.stroke);
svg.addLine(canvas, pl2, pay, p4, pay, opt.stroke);
drawCoil1(0);
drawCoil1(1);
drawCoil1(2);
drawCoil1(3);
svg.addText(canvas, point1.text, pl1, pay - opt.textMargin, opt);
if(point1.name) {
svg.addText(canvas, point1.name, pl1, pay - opt.textMargin * 2, opt);
}
}, function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
function drawCoil1(num) {
var points = "";
points += "M " + pax + " " + (pl1 + opt.inductorLength * num / 4) + " ";
points += "a " + opt.inductorLength / 8 + " " + opt.inductorLength / 8 + " ";
points += "90 0 1 0 " + opt.inductorLength / 4;
svg.addPath(canvas, points, opt.fill, opt.stroke);
}
svg.addLine(canvas, pax, p3, pax, pl1, opt.stroke);
svg.addLine(canvas, pax, pl2, pax, p4, opt.stroke);
drawCoil1(0);
drawCoil1(1);
drawCoil1(2);
drawCoil1(3);
if(point1.name) {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2 + opt.textMargin / 2, opt);
svg.addText(canvas, point1.name, pax + opt.textMargin, p3 + (p4 - p3) / 2 - opt.textMargin / 2, opt);
} else {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2, opt);
}
}
),
drawVoltageAC: makeDrawing(
opt.voltageACRadius * 2,
function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
var points = "";
svg.addLine(canvas, p3, pay, pl1, pay, opt.stroke);
svg.addLine(canvas, pl2, pay, p4, pay, opt.stroke);
points += "M " + ((p4 + p3) / 2) + " " + pay + " ";
points += "q " + (-opt.voltageACx / 2) + " " + (-opt.voltageACy / 2) + " " + (-opt.voltageACx) + " 0";
svg.addPath(canvas, points, opt.fill, opt.stroke);
points += "M " + ((p4 + p3) / 2) + " " + pay + " ";
points += "q " + (opt.voltageACx / 2) + " " + (opt.voltageACy / 2) + " " + (opt.voltageACx) + " 0";
svg.addPath(canvas, points, opt.fill, opt.stroke);
svg.addCircle(canvas, (p4 + p3) / 2, pay, opt.voltageACRadius, opt.stroke, opt.voltageACFill);
svg.addText(canvas, point1.text, pl1, pay - opt.textMargin, opt);
if(point1.name) {
svg.addText(canvas, point1.name, pl1, pay - opt.textMargin * 2, opt);
}
}, function(point1, point2, pax, pay, pbx, pby, p1x, p1y, p2x, p2y, pl1, pl2, p3, p4) {
var points = "";
svg.addLine(canvas, pax, p3, pax, pl1, opt.stroke);
svg.addLine(canvas, pax, pl2, pax, p4, opt.stroke);
points += "M " + pax + " " + ((p4 + p3) / 2) + " ";
points += "q " + (-opt.voltageACx / 2) + " " + (-opt.voltageACy / 2) + " " + (-opt.voltageACx) + " 0";
svg.addPath(canvas, points, opt.fill, opt.stroke);
points += "M " + pax + " " + ((p4 + p3) / 2) + " ";
points += "q " + (opt.voltageACx / 2) + " " + (opt.voltageACy / 2) + " " + (opt.voltageACx) + " 0";
svg.addPath(canvas, points, opt.fill, opt.stroke);
svg.addCircle(canvas, pax, (p4 + p3) / 2, opt.voltageACRadius, opt.stroke, opt.voltageACFill);
if(point1.name) {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2 + opt.textMargin / 2, opt);
svg.addText(canvas, point1.name, pax + opt.textMargin, p3 + (p4 - p3) / 2 - opt.textMargin / 2, opt);
} else {
svg.addText(canvas, point1.text, pax + opt.textMargin, p3 + (p4 - p3) / 2, opt);
}
}
),
getCanvas: function() {
return canvas;
}
};
return me;
}
module.exports = createDrawer;