kmap
Version:
Karnagh Map Editor
209 lines (173 loc) • 6.32 kB
JavaScript
import {MessageDialog} from './MessageDialog';
/**
* The actual Karnaugh Map
* @param main
* @param element
* @constructor
*/
export const Map = function(main, element) {
this.main = main;
this.element = element;
this.selected = [];
let topLeft, botRight, canvas;
const initialize = () => {
let table = document.createElement('table');
table.classList.add('kmap-cl');
element.appendChild(table);
// Make a local copy of the labels, converting
// _1 to <sub>1</sub>
const labels = [];
for(const label of main.options.labels) {
labels.push(label.replace(/_([a-zA-Z0-9])*/g, '<sub>$1</sub>'));
}
var left, right, rest, colheads;
if(+main.options.size === 2) {
let A = labels[0];
let B = labels[1];
left=B;
right=A;
rest = "<th>" + A + "'</th><th>" + A + "</th>";
colheads = [B + "'", B];
} else if(+main.options.size === 3) {
let A = labels[0];
let B = labels[1];
let C = labels[2];
left=C;
right=A + B;
rest = "<th>" + A + "'" + B + "'</th><th>" + A + "'" + B +
"</th><th>" + A + B + "</th><th>" + A + B + "'</th>";
colheads = [C + "'", C];
} else {
let A = labels[0];
let B = labels[1];
let C = labels[2];
let D = labels[3];
left=C + D;
right=A + B;
rest = "<th>" + A + "'" + B + "'</th><th>" + A + "'" + B + "</th><th>" +
A + B + "</th><th>" + A + B + "'</th>";
colheads = [C + "'" + D + "'", C + "'" + D, C + D, C + D + "'"];
}
/*
* Top row first
*/
let tr = document.createElement('tr');
tr.innerHTML = '<th><div class="kmap-cl-left">' + left +
'</div><div class="kmap-cl-line"></div><div class="kmap-cl-right">' + right + '</div></th>' +
rest;
table.appendChild(tr);
/*
* Rest of the table
*/
let rows = +main.options.size === 4 ? 4 : 2;
let cols = +main.options.size === 2 ? 2 : 4;
for(let r=1; r<=rows; r++) {
tr = document.createElement('tr');
tr.innerHTML = '<th>' + colheads[r-1] + '</th>';
for(let c=1; c<=cols; c++) {
const td = make_cell(c, r);
tr.appendChild(td);
if(r === 1 && c === 1) {
topLeft = td;
} else if(r === rows && c === cols) {
botRight = td;
}
}
table.appendChild(tr);
}
canvas = document.createElement('canvas');
canvas.setAttribute('width', '1000');
canvas.setAttribute('height', '1000');
this.canvas = canvas;
element.appendChild(canvas);
setTimeout(() => {
set_canvas();
}, 0);
window.addEventListener('resize', set_canvas);
}
this.get_canvas = function() {
return this.canvas;
}
this.destroy = function() {
window.removeEventListener('resize', set_canvas);
}
function set_canvas() {
const tl = {left: topLeft.offsetLeft, top: topLeft.offsetTop};
const br = {left: botRight.offsetLeft, top: botRight.offsetTop};
canvas.style.top = tl.top + 'px';
canvas.style.left = tl.left + 'px';
canvas.style.width = (br.left - tl.left + botRight.offsetWidth) + 'px';
canvas.style.height = (br.top - tl.top + botRight.offsetHeight) + 'px';
}
const make_cell = (c, r) => {
let td = document.createElement('td');
let minterm = to_minterm(c, r);
let bit = '0';
for(var i=0; i<main.options.minterms.length; i++) {
if(minterm === +main.options.minterms[i]) {
bit = '1';
break;
}
}
for(i=0; i<main.options.dontcare.length; i++) {
if(minterm === +main.options.dontcare[i]) {
bit = 'X';
break;
}
}
if(main.options.labelMinterms) {
td.innerHTML = '<span class="minterm">m' + minterm + '</span>' + bit;
} else {
td.innerHTML = bit;
}
td.addEventListener('click', (event) => {
event.preventDefault();
if(this.main.options.strict && bit === '0') {
let html = '<p>You are only allowed to select cells that are either true ' +
'or set to don\'t care.</p><p>We are grouping minterms that all are true ' +
'so we can minimize the circuit. So, only true cells can be grouped.</p>';
const dlg = new MessageDialog(main, "You can't do that", html);
dlg.open();
return;
}
if(td.classList.contains("kmap-cl-selected")) {
td.classList.remove("kmap-cl-selected");
let n = this.selected.indexOf(minterm);
if(n > -1) {
this.selected.splice(n, 1);
}
} else {
td.classList.add("kmap-cl-selected");
if(!is_selected(minterm)) {
this.selected.push(minterm);
this.selected.sort(function(a, b) {
return a - b;
});
}
}
});
return td;
}
const to_minterm = (c, r) => {
let map;
if(+this.main.options.size === 2) {
map = [[0, 2], [1, 3]];
} else if(+this.main.options.size === 3) {
map = [[0, 2, 6, 4], [1, 3, 7, 5]];
} else {
map = [[0, 4, 12, 8], [1, 5, 13, 9], [3, 7, 15, 11], [2, 6, 14, 10]];
}
return map[r-1][c-1];
}
const is_selected = (minterm) => {
return this.selected.indexOf(minterm) > -1; //
}
this.clear = function() {
this.selected = [];
const tds = this.element.querySelectorAll('td');
for(let td of tds) {
td.classList.remove('kmap-cl-selected');
}
}
initialize();
}