periodic-table-cli
Version:
An interactive Periodic Table of Elements app for the console!
897 lines (789 loc) • 44.4 kB
JavaScript
const periodic_table = require('./index.js');
const { SelectModes, DisplayModes, Layout } = require('./statecontroller.js');
const data = require('./data.js');
const { Utils } = require('./utils.js');
const { SearchResultType } = require('./searchprocessor.js');
const { Renderer } = require('./renderer.js');
const { Colors } = require('./colors.js');
class Dashboard {
HORIZONTAL_RATIO = 0.5;
VERTICAL_RATIO = 0.333;
ELEMENTS_POS = { x: 3, y: 2 };
ELEMENT_WIDTH = 6;
ELEMENT_HEIGHT = 3;
BG_COLOR = Colors.BLACK;
FG_COLOR = Colors.WHITE;
DISPLAY_CONFIG = { x: 117, y: 36, length: 36 };
CONNECTORS_POS = [
{ y: 18, x: 16 }, { y: 18, x: 17 }, { y: 18, x: 18 }, { y: 18, x: 19 }, { y: 18, x: 20 },
{ y: 19, x: 18 }, { y: 20, x: 18 }, { y: 21, x: 16 }, { y: 21, x: 17 }, { y: 21, x: 18 },
{ y: 21, x: 19 }, { y: 21, x: 20 }, { y: 22, x: 18 }, { y: 23, x: 18 }, { y: 24, x: 18 },
{ y: 24, x: 17 }, { y: 24, x: 16 }, { y: 24, x: 15 }, { y: 24, x: 14 }, { y: 24, x: 13 },
{ y: 25, x: 13 }, { y: 26, x: 13 }, { y: 27, x: 13 }, { y: 28, x: 13 }, { y: 29, x: 13 },
{ y: 26, x: 14 }, { y: 29, x: 14 },
];
FAMILIES_CONFIG = {
// Row 1
'Alkali metal': { x: 7, y: 36, length: 19, color: Colors.RED },
'Alkaline earth metal': { x: 27, y: 36, length: 27, color: Colors.ORANGE },
'Transition metal': { x: 55, y: 36, length: 23, color: Colors.YELLOW },
'Post-transition metal': { x: 79, y: 36, length: 28, color: Colors.DARK_YELLOW },
// Row 2
'Metalloid': { x: 7, y: 37, length: 19, color: Colors.GREEN },
'Nonmetal': { x: 27, y: 37, length: 27, color: Colors.DARK_GREEN },
'Halogen': { x: 55, y: 37, length: 23, color: Colors.SKY_BLUE },
'Noble gas': { x: 79, y: 37, length: 28, color: Colors.BLUE },
// Row 3
'Lanthanide': { x: 7, y: 38, length: 19, color: Colors.MAGENTA },
'Actinide': { x: 27, y: 38, length: 27, color: Colors.PURPLE },
};
SHELLS_CONFIG = {
's-shell': { x: 16, y: 43, length: 13, color: Colors.RED },
'p-shell': { x: 39, y: 43, length: 13, color: Colors.YELLOW },
'd-shell': { x: 62, y: 43, length: 13, color: Colors.GREEN },
'f-shell': { x: 85, y: 43, length: 13, color: Colors.BLUE },
};
STATES_CONFIG = {
'Solid': { color: Colors.WHITE },
'Solid **': { color: Colors.GRAY },
'Liquid': { color: Colors.RED },
'Liquid **': { color: Colors.DARK_RED },
'Gas': { color: Colors.SKY_BLUE },
'Gas **': { color: Colors.BLUE },
};
VALENCE_ELECTRON_CONFIG = {
colors: {
1: { color: Colors.PURPLE },
2: { color: Colors.MAGENTA },
3: { color: Colors.BLUE },
4: { color: Colors.SKY_BLUE },
5: { color: Colors.GREEN },
6: { color: Colors.YELLOW },
7: { color: Colors.ORANGE },
8: { color: Colors.RED },
},
minValue: 1,
maxValue: 8,
};
VALENCY_CONFIG = {
colors: {
0: { color: Colors.SKY_BLUE },
1: { color: Colors.GREEN },
2: { color: Colors.YELLOW },
3: { color: Colors.ORANGE },
4: { color: Colors.RED },
},
minValue: 0,
maxValue: 4,
};
RADIOACTIVE_CONFIG = {
true: { color: Colors.RED },
false: { color: Colors.GREEN },
};
OCCURRENCE_CONFIG = {
'Natural': { color: Colors.SKY_BLUE },
'Rare': { color: Colors.YELLOW },
'Synthetic': { color: Colors.ORANGE },
};
YEAR_CONFIG = {
minValue: 1669,
maxValue: 2010,
colors: {
ANCIENT: Colors.WHITE,
},
};
PERIOD_POS = {
1: { x: 1, y: 3, length: 1 },
2: { x: 1, y: 6, length: 1 },
3: { x: 1, y: 9, length: 1 },
4: { x: 1, y: 12, length: 1 },
5: { x: 1, y: 15, length: 1 },
6: { x: 1, y: 18, length: 1 },
7: { x: 1, y: 21, length: 1 },
};
GROUP_POS = {
1: { x: 6, y: 1, length: 1 },
2: { x: 12, y: 4, length: 1 },
3: { x: 18, y: 10, length: 1 },
4: { x: 24, y: 10, length: 1 },
5: { x: 30, y: 10, length: 1 },
6: { x: 36, y: 10, length: 1 },
7: { x: 42, y: 10, length: 1 },
8: { x: 48, y: 10, length: 1 },
9: { x: 54, y: 10, length: 1 },
10: { x: 59, y: 10, length: 2 },
11: { x: 65, y: 10, length: 2 },
12: { x: 71, y: 10, length: 2 },
13: { x: 77, y: 4, length: 2 },
14: { x: 83, y: 4, length: 2 },
15: { x: 89, y: 4, length: 2 },
16: { x: 95, y: 4, length: 2 },
17: { x: 101, y: 4, length: 2 },
18: { x: 107, y: 1, length: 2 },
};
PANEL_CONFIG = {
TOP_POS: { x: 117, y: 3 },
LIST_POS: { x: 117, y: 5 },
WIDTH: 36,
HEIGHT: 26,
};
TITLES = {
THE_PERIODIC_TABLE_OF_ELEMENTS: { x: 30, y: 2, length: 30 }, // The Periodic Table of Elements
ELEMENT_FAMILIES: { x: 49, y: 34, length: 16 }, // Element Families
ELEMENT_CONFIGURATIONS: { x: 46, y: 41, length: 23 }, // Element Configurations
DISPLAY_MODES: { x: 129, y: 34, length: 12 }, // Display Mode
CONTROLS: { x: 131, y: 39, length: 8 }, // Controls
};
SEARCH_CONFIG = {
colors: {
RESULTS: Colors.GREEN,
RESULTS_FOCUSED: Colors.MID_GREEN,
NO_RESULTS: Colors.RED,
},
};
constructor() {
this.board = this._parseBoard();
this.scrolling = { x: 0, y: 0 };
this._initDataOnBoard();
this._saveBoard();
}
_initDataOnBoard() {
const elements = Utils.getElements(data.elements);
for (var r = 0; r < Layout.PeriodicTable.length; r++) {
for (var c = 0; c < Layout.PeriodicTable[r].length; c++) {
if (Layout.PeriodicTable[r][c] !== undefined && Layout.PeriodicTable[r][c] > 0) {
const xOffset = this.ELEMENTS_POS.x;
var yOffset = this.ELEMENTS_POS.y;
if (Utils.isBottomSection(Layout.PeriodicTable[r][c])) {
yOffset += 2;
}
// Atomic number
if (Layout.PeriodicTable[r][c] < 10) {
this._setText(xOffset + (c * this.ELEMENT_WIDTH) + 3, yOffset + (r * this.ELEMENT_HEIGHT) + 1, elements[Layout.PeriodicTable[r][c]]['atomicNumber'].toString());
} else {
this._setText(xOffset + (c * this.ELEMENT_WIDTH) + 2, yOffset + (r * this.ELEMENT_HEIGHT) + 1, elements[Layout.PeriodicTable[r][c]]['atomicNumber'].toString());
}
// Symbol
this._setText(xOffset + (c * this.ELEMENT_WIDTH) + 3, yOffset + (r * this.ELEMENT_HEIGHT) + 2, elements[Layout.PeriodicTable[r][c]]['symbol']);
}
}
}
for (const family in this.FAMILIES_CONFIG) {
const familyConfig = this.FAMILIES_CONFIG[family];
this._setText(familyConfig.x + 3, familyConfig.y, data.families[family].name, familyConfig.length - 3, 'left');
}
for (const shell in this.SHELLS_CONFIG) {
const shellConfig = this.SHELLS_CONFIG[shell];
this._setText(shellConfig.x + 3, shellConfig.y, data.shells[shell].name, shellConfig.length - 3, 'left');
}
}
getNumberOfLines() {
return this.board.length;
}
_parseBoard() {
const parts = periodic_table.dashboard.split('\n');
const board = [];
for (const part of parts) {
const row = [];
for (var i = 0; i < part.length; i++) {
row.push({ character: part.charAt(i) });
}
board.push(row);
}
return board;
}
_saveBoard() {
for (var r = 0; r < this.board.length; r++) {
for (var c = 0; c < this.board[r].length; c++) {
this.board[r][c].initCharacter = this.board[r][c].character;
}
}
}
_resetBoard() {
for (var r = 0; r < this.board.length; r++) {
for (var c = 0; c < this.board[r].length; c++) {
this.board[r][c].character = this.board[r][c].initCharacter;
this.board[r][c].config = {};
}
}
}
_setBackground() {
for (var r = 0; r < this.board.length; r++) {
for (var c = 0; c < this.board[r].length; c++) {
this.board[r][c].config.backgroundColor = this.BG_COLOR.BG;
this.board[r][c].config.foregroundColor = this.FG_COLOR.FG;
}
}
}
_makeBold(x, y, length) {
for (var c = 0; c < length; c++) {
this.board[y][x + c].config.bold = true;
}
}
_setTextColor(x, y, length, color, bold) {
for (var c = 0; c < length; c++) {
this.board[y][x + c].config.foregroundColor = color.FG;
this.board[y][x + c].config.bold = bold;
}
}
_setHighlightColor(x, y, length, color) {
for (var c = 0; c < length; c++) {
this.board[y][x + c].config.backgroundColor = color.BG;
this.board[y][x + c].config.foregroundColor = Colors.BLACK.FG;
}
}
_setText(x, y, text, maxLength=undefined, type=undefined) {
var offset = 0;
if (maxLength !== undefined && type !== undefined) {
if (type === 'center') {
offset = Math.max(parseInt((maxLength - text.length) / 2), 0);
} else if (type === 'right') {
offset = Math.max(maxLength - text.length, 0);
}
}
for (var i = 0; i < text.length; i++) {
this.board[y][x + offset + i].character = '' + text[i];
}
}
_decorateTitles() {
for (const title in this.TITLES) {
this._makeBold(this.TITLES[title].x, this.TITLES[title].y, this.TITLES[title].length);
}
}
_getElementFillColor(element, displayMode) {
if (displayMode === DisplayModes.STANDARD) {
return undefined;
} else if (displayMode === DisplayModes.FAMILIES) {
return this.FAMILIES_CONFIG[element.display.family].color;
} else if (displayMode === DisplayModes.SHELLS) {
return this.SHELLS_CONFIG[element.display.shell].color;
} else if (displayMode === DisplayModes.STATES) {
return this.STATES_CONFIG[element.display.state].color;
} else if (displayMode === DisplayModes.VALENCE_ELECTRONS) {
const config = this.VALENCE_ELECTRON_CONFIG.colors[element.display.valenceElectrons];
return config ? config.color : undefined;
} else if (displayMode === DisplayModes.VALENCY) {
const config = this.VALENCY_CONFIG.colors[element.display.valency];
return config ? config.color : undefined;
} else if (displayMode === DisplayModes.RADIOACTIVE) {
const config = this.RADIOACTIVE_CONFIG[element.display.radioactive];
return config ? config.color : undefined;
} else if (displayMode === DisplayModes.OCCURRENCE) {
const config = this.OCCURRENCE_CONFIG[element.display.occurrence];
return config ? config.color : undefined;
} else if (element.display.meter !== undefined) {
const colorIndex = Utils.getBucketValue(element.display.meter, Colors.METER_COLORS.length);
return Colors.METER_COLORS[colorIndex];
} else if (element.display.isAncient) {
return this.YEAR_CONFIG.colors.ANCIENT;
}
}
_decorateElement(x, y, color, fillColor, focused, displayMode) {
// Lines
this.board[y][x].config.foregroundColor = color.FG;
this.board[y + 1][x].config.foregroundColor = color.FG;
this.board[y + 2][x].config.foregroundColor = color.FG;
this.board[y + 3][x].config.foregroundColor = color.FG;
this.board[y][x + 1].config.foregroundColor = color.FG;
this.board[y][x + 2].config.foregroundColor = color.FG;
this.board[y][x + 3].config.foregroundColor = color.FG;
this.board[y][x + 4].config.foregroundColor = color.FG;
this.board[y][x + 5].config.foregroundColor = color.FG;
this.board[y][x + 6].config.foregroundColor = color.FG;
this.board[y + 1][x + 6].config.foregroundColor = color.FG;
this.board[y + 2][x + 6].config.foregroundColor = color.FG;
this.board[y + 3][x + 6].config.foregroundColor = color.FG;
this.board[y + 3][x + 1].config.foregroundColor = color.FG;
this.board[y + 3][x + 2].config.foregroundColor = color.FG;
this.board[y + 3][x + 3].config.foregroundColor = color.FG;
this.board[y + 3][x + 4].config.foregroundColor = color.FG;
this.board[y + 3][x + 5].config.foregroundColor = color.FG;
// Text
if (focused) {
// Atomic number
this.board[y + 1][x + 2].config.foregroundColor = color.FG;
this.board[y + 1][x + 3].config.foregroundColor = color.FG;
this.board[y + 1][x + 4].config.foregroundColor = color.FG;
this.board[y + 1][x + 2].config.bold = true;
this.board[y + 1][x + 3].config.bold = true;
this.board[y + 1][x + 4].config.bold = true;
// Element
var elementColor = Colors.WHITE;
if (displayMode !== DisplayModes.STANDARD && fillColor !== undefined) {
elementColor = Colors.BLACK;
}
this.board[y + 2][x + 2].config.foregroundColor = elementColor.FG;
this.board[y + 2][x + 3].config.foregroundColor = elementColor.FG;
this.board[y + 2][x + 4].config.foregroundColor = elementColor.FG;
this.board[y + 2][x + 2].config.bold = true;
this.board[y + 2][x + 3].config.bold = true;
this.board[y + 2][x + 4].config.bold = true;
} else {
if (displayMode !== DisplayModes.STANDARD && fillColor !== undefined) {
// Atomic number
this.board[y + 1][x + 2].config.foregroundColor = Colors.BLACK.FG;
this.board[y + 1][x + 3].config.foregroundColor = Colors.BLACK.FG;
this.board[y + 1][x + 4].config.foregroundColor = Colors.BLACK.FG;
// Element
this.board[y + 2][x + 2].config.foregroundColor = Colors.BLACK.FG;
this.board[y + 2][x + 3].config.foregroundColor = Colors.BLACK.FG;
this.board[y + 2][x + 4].config.foregroundColor = Colors.BLACK.FG;
} else {
// Atomic number
this.board[y + 1][x + 2].config.foregroundColor = Colors.GRAY.FG;
this.board[y + 1][x + 3].config.foregroundColor = Colors.GRAY.FG;
this.board[y + 1][x + 4].config.foregroundColor = Colors.GRAY.FG;
// Element
this.board[y + 2][x + 2].config.foregroundColor = Colors.WHITE.FG;
this.board[y + 2][x + 3].config.foregroundColor = Colors.WHITE.FG;
this.board[y + 2][x + 4].config.foregroundColor = Colors.WHITE.FG;
}
}
// Fill color
var topColor = this.BG_COLOR;
if (fillColor !== undefined && !focused) {
topColor = fillColor;
}
this.board[y + 1][x + 1].config.backgroundColor = topColor.BG;
this.board[y + 1][x + 2].config.backgroundColor = topColor.BG;
this.board[y + 1][x + 3].config.backgroundColor = topColor.BG;
this.board[y + 1][x + 4].config.backgroundColor = topColor.BG;
this.board[y + 1][x + 5].config.backgroundColor = topColor.BG;
if (fillColor !== undefined) {
this.board[y + 2][x + 1].config.backgroundColor = fillColor.BG;
this.board[y + 2][x + 2].config.backgroundColor = fillColor.BG;
this.board[y + 2][x + 3].config.backgroundColor = fillColor.BG;
this.board[y + 2][x + 4].config.backgroundColor = fillColor.BG;
this.board[y + 2][x + 5].config.backgroundColor = fillColor.BG;
}
}
_applyConfigToElements(config) {
// Lines
for (var point of this.CONNECTORS_POS) {
this.board[point.y][point.x].config.foregroundColor = Colors.GRAY.FG;
}
// Draw unselected
for (var r = 0; r < Layout.PeriodicTable.length; r++) {
for (var c = 0; c < Layout.PeriodicTable[r].length; c++) {
if (Layout.PeriodicTable[r][c] !== undefined && Layout.PeriodicTable[r][c] > 0) {
const elementConfig = config.elements[Layout.PeriodicTable[r][c]];
const xOffset = this.ELEMENTS_POS.x;
var yOffset = this.ELEMENTS_POS.y;
if (Utils.isBottomSection(elementConfig.atomicNumber)) {
yOffset += 2;
}
const fillColor = this._getElementFillColor(elementConfig, config.displayMode);
var focusColor = Colors.WHITE;
if (config.shells.selected === undefined && config.families.selected === undefined && config.displayMode === DisplayModes.STANDARD) {
focusColor = Colors.FOCUS_BLUE;
}
this._decorateElement(xOffset + (c * this.ELEMENT_WIDTH), yOffset + (r * this.ELEMENT_HEIGHT), focusColor, fillColor, false, config.displayMode);
}
}
}
for (const family in this.FAMILIES_CONFIG) {
const familyConfig = this.FAMILIES_CONFIG[family];
this._setTextColor(familyConfig.x, familyConfig.y, familyConfig.length, Colors.GRAY, false);
}
for (const shell in this.SHELLS_CONFIG) {
const shellConfig = this.SHELLS_CONFIG[shell];
this._setTextColor(shellConfig.x, shellConfig.y, shellConfig.length, Colors.GRAY, false);
}
// Draw selected
for (var r = 0; r < Layout.PeriodicTable.length; r++) {
for (var c = 0; c < Layout.PeriodicTable[r].length; c++) {
if (Layout.PeriodicTable[r][c] > 0 && config.elements[Layout.PeriodicTable[r][c]] !== undefined && config.elements[Layout.PeriodicTable[r][c]].selected !== undefined) {
const elementConfig = config.elements[Layout.PeriodicTable[r][c]];
const xOffset = this.ELEMENTS_POS.x;
var yOffset = this.ELEMENTS_POS.y;
if (Utils.isBottomSection(elementConfig.atomicNumber)) {
yOffset += 2;
}
const fillColor = this._getElementFillColor(elementConfig, config.displayMode);
if (elementConfig.selected.type === SelectModes.ELEMENT) {
this._decorateElement(xOffset + (c * this.ELEMENT_WIDTH), yOffset + (r * this.ELEMENT_HEIGHT), Colors.FOCUS_GOLD, fillColor, true, config.displayMode);
} else if (elementConfig.selected.type === SelectModes.FAMILY) {
const familyConfig = this.FAMILIES_CONFIG[config.families.selected];
this._decorateElement(xOffset + (c * this.ELEMENT_WIDTH), yOffset + (r * this.ELEMENT_HEIGHT), familyConfig.color, fillColor, true, config.displayMode);
} else if (elementConfig.selected.type === SelectModes.SHELL) {
const shellConfig = this.SHELLS_CONFIG[config.shells.selected];
this._decorateElement(xOffset + (c * this.ELEMENT_WIDTH), yOffset + (r * this.ELEMENT_HEIGHT), shellConfig.color, fillColor, true, config.displayMode);
}
}
}
}
if (config && config.families) {
if (config.families.indicated && this.FAMILIES_CONFIG[config.families.indicated]) {
const familyConfig = this.FAMILIES_CONFIG[config.families.indicated];
this._setTextColor(familyConfig.x, familyConfig.y, familyConfig.length, Colors.FOCUS_GOLD, true);
} else if (config.families.selected && this.FAMILIES_CONFIG[config.families.selected]) {
const familyConfig = this.FAMILIES_CONFIG[config.families.selected];
this._setHighlightColor(familyConfig.x, familyConfig.y, familyConfig.length, familyConfig.color);
}
}
if (config.displayMode === DisplayModes.FAMILIES) {
for (const familyName in this.FAMILIES_CONFIG) {
const familyConfig = this.FAMILIES_CONFIG[familyName];
this._setHighlightColor(familyConfig.x, familyConfig.y, 2, familyConfig.color);
}
}
if (config && config.shells) {
if (config.shells.indicated && this.SHELLS_CONFIG[config.shells.indicated]) {
const shellConfig = this.SHELLS_CONFIG[config.shells.indicated];
this._setTextColor(shellConfig.x, shellConfig.y, shellConfig.length, Colors.FOCUS_GOLD, true);
} else if (config.shells.selected && this.SHELLS_CONFIG[config.shells.selected]) {
const shellConfig = this.SHELLS_CONFIG[config.shells.selected];
this._setHighlightColor(shellConfig.x, shellConfig.y, shellConfig.length, shellConfig.color);
}
}
if (config.displayMode === DisplayModes.SHELLS) {
for (const shellName in this.SHELLS_CONFIG) {
const shellsConfig = this.SHELLS_CONFIG[shellName];
this._setHighlightColor(shellsConfig.x, shellsConfig.y, 2, shellsConfig.color);
}
}
if (config && config.period && this.PERIOD_POS[config.period]) {
const periodConfig = this.PERIOD_POS[config.period];
this._setTextColor(periodConfig.x, periodConfig.y, periodConfig.length, Colors.FOCUS_GOLD, false);
}
if (config && config.group && this.GROUP_POS[config.group]) {
const groupConfig = this.GROUP_POS[config.group];
this._setTextColor(groupConfig.x, groupConfig.y, groupConfig.length, Colors.FOCUS_GOLD, false);
}
}
_setDisplayMode(config) {
if (config.displayMode === DisplayModes.STANDARD) {
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'STANDARD', this.DISPLAY_CONFIG.length, 'center');
} else if (config.displayMode === DisplayModes.FAMILIES) {
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'ELEMENT FAMILIES', this.DISPLAY_CONFIG.length, 'center');
this._setHighlightColor(this.TITLES.ELEMENT_FAMILIES.x - 2, this.TITLES.ELEMENT_FAMILIES.y, this.TITLES.ELEMENT_FAMILIES.length + 4, Colors.WHITE);
} else if (config.displayMode === DisplayModes.SHELLS) {
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'ELECTRON CONFIGURATIONS', this.DISPLAY_CONFIG.length, 'center');
this._setHighlightColor(this.TITLES.ELEMENT_CONFIGURATIONS.x - 2, this.TITLES.ELEMENT_CONFIGURATIONS.y, this.TITLES.ELEMENT_CONFIGURATIONS.length + 4, Colors.WHITE);
} else if (config.displayMode === DisplayModes.STATES) {
const sectionLength = this.DISPLAY_CONFIG.length / 3;
this._setHighlightColor(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, sectionLength - 1, this.STATES_CONFIG['Solid'].color);
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'SOLID', sectionLength - 1, 'center');
this._setHighlightColor(this.DISPLAY_CONFIG.x + sectionLength, this.DISPLAY_CONFIG.y, sectionLength, this.STATES_CONFIG['Liquid'].color);
this._setText(this.DISPLAY_CONFIG.x + sectionLength, this.DISPLAY_CONFIG.y, 'LIQUID', sectionLength, 'center');
this._setHighlightColor(this.DISPLAY_CONFIG.x + (2 * sectionLength) + 1, this.DISPLAY_CONFIG.y, sectionLength - 1, this.STATES_CONFIG['Gas'].color);
this._setText(this.DISPLAY_CONFIG.x + (2 * sectionLength) + 1, this.DISPLAY_CONFIG.y, 'GAS', sectionLength - 1, 'center');
} else if (config.displayMode === DisplayModes.VALENCE_ELECTRONS) {
const sectionLength = this.DISPLAY_CONFIG.length / 2;
const partLength = 2;
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'VALENCE ELECTRONS', sectionLength, 'center');
var count = 0;
for (let i = this.VALENCE_ELECTRON_CONFIG.minValue; i <= this.VALENCE_ELECTRON_CONFIG.maxValue; i++) {
this._setHighlightColor(this.DISPLAY_CONFIG.x + sectionLength + (count * partLength) + 2, this.DISPLAY_CONFIG.y, partLength, this.VALENCE_ELECTRON_CONFIG.colors[i].color);
this._setText(this.DISPLAY_CONFIG.x + sectionLength + (count * partLength) + 2, this.DISPLAY_CONFIG.y, ' ' + i, partLength, 'left');
count++;
}
} else if (config.displayMode === DisplayModes.VALENCY) {
const sectionLength = this.DISPLAY_CONFIG.length / 2;
const partLength = 3;
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'VALENCY', sectionLength, 'center');
var count = 0;
for (let i = this.VALENCY_CONFIG.minValue; i <= this.VALENCY_CONFIG.maxValue; i++) {
this._setHighlightColor(this.DISPLAY_CONFIG.x + sectionLength + (count * partLength) + 3, this.DISPLAY_CONFIG.y, partLength, this.VALENCY_CONFIG.colors[i].color);
this._setText(this.DISPLAY_CONFIG.x + sectionLength + (count * partLength) + 3, this.DISPLAY_CONFIG.y, String(i), partLength, 'center');
count++;
}
} else if (config.displayMode === DisplayModes.RADIOACTIVE) {
const sectionLength = this.DISPLAY_CONFIG.length / 2;
this._setHighlightColor(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, sectionLength - 1, this.RADIOACTIVE_CONFIG[true].color);
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'RADIOACTIVE', sectionLength - 1, 'center');
this._setHighlightColor(this.DISPLAY_CONFIG.x + sectionLength, this.DISPLAY_CONFIG.y, sectionLength, this.RADIOACTIVE_CONFIG[false].color);
this._setText(this.DISPLAY_CONFIG.x + sectionLength, this.DISPLAY_CONFIG.y, 'STABLE', sectionLength, 'center');
} else if (config.displayMode === DisplayModes.OCCURRENCE) {
const sectionLength = this.DISPLAY_CONFIG.length / 3;
this._setHighlightColor(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, sectionLength - 1, this.OCCURRENCE_CONFIG['Natural'].color);
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'NATURAL', sectionLength - 1, 'center');
this._setHighlightColor(this.DISPLAY_CONFIG.x + sectionLength, this.DISPLAY_CONFIG.y, sectionLength, this.OCCURRENCE_CONFIG['Rare'].color);
this._setText(this.DISPLAY_CONFIG.x + sectionLength, this.DISPLAY_CONFIG.y, 'RARE', sectionLength, 'center');
this._setHighlightColor(this.DISPLAY_CONFIG.x + (2 * sectionLength) + 1, this.DISPLAY_CONFIG.y, sectionLength - 1, this.OCCURRENCE_CONFIG['Synthetic'].color);
this._setText(this.DISPLAY_CONFIG.x + (2 * sectionLength) + 1, this.DISPLAY_CONFIG.y, 'SYNTHETIC', sectionLength - 1, 'center');
} else if (config.displayMode === DisplayModes.YEAR) {
const sectionLength = this.DISPLAY_CONFIG.length / 2;
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, 'YEAR', sectionLength - 9, 'center');
this._setHighlightColor(this.DISPLAY_CONFIG.x + sectionLength - 8, this.DISPLAY_CONFIG.y, 9, this.YEAR_CONFIG.colors.ANCIENT);
this._setText(this.DISPLAY_CONFIG.x + sectionLength - 8, this.DISPLAY_CONFIG.y, 'ANCIENT', 9, 'center');
for (let i = 0; i < Colors.METER_COLORS.length; i++) {
this._setHighlightColor(this.DISPLAY_CONFIG.x + sectionLength + i + 2, this.DISPLAY_CONFIG.y, 1, Colors.METER_COLORS[i]);
}
this._setTextColor(this.DISPLAY_CONFIG.x + sectionLength + 3, this.DISPLAY_CONFIG.y, 4, Colors.BLACK, false);
this._setText(this.DISPLAY_CONFIG.x + sectionLength + 3, this.DISPLAY_CONFIG.y, String(this.YEAR_CONFIG.minValue), 4, 'left');
this._setTextColor(this.DISPLAY_CONFIG.x + (2 * sectionLength) - 5, this.DISPLAY_CONFIG.y, 4, Colors.BLACK, false);
this._setText(this.DISPLAY_CONFIG.x + (2 * sectionLength) - 5, this.DISPLAY_CONFIG.y, String(this.YEAR_CONFIG.maxValue), 4, 'left');
} else if (config.displayMode && config.displayMode.isMeter) {
const sectionLength = this.DISPLAY_CONFIG.length / 2;
this._setText(this.DISPLAY_CONFIG.x, this.DISPLAY_CONFIG.y, this._getFieldName(config.displayMode.key).toUpperCase(), sectionLength, 'center');
for (let i = 0; i < Colors.METER_COLORS.length; i++) {
this._setHighlightColor(this.DISPLAY_CONFIG.x + sectionLength + i + 2, this.DISPLAY_CONFIG.y, 1, Colors.METER_COLORS[i]);
}
this._setTextColor(this.DISPLAY_CONFIG.x + sectionLength + 3, this.DISPLAY_CONFIG.y, 3, Colors.BLACK, false);
this._setText(this.DISPLAY_CONFIG.x + sectionLength + 3, this.DISPLAY_CONFIG.y, 'MIN', 3, 'left');
this._setTextColor(this.DISPLAY_CONFIG.x + (2 * sectionLength) - 4, this.DISPLAY_CONFIG.y, 3, Colors.BLACK, false);
this._setText(this.DISPLAY_CONFIG.x + (2 * sectionLength) - 4, this.DISPLAY_CONFIG.y, 'MAX', 3, 'left');
}
}
_getFieldName(key) {
for (const data of Layout.PanelData) {
if (data.key === key) {
return data.name;
}
}
return undefined;
}
_getFieldIndex(key) {
for (let i = 0; i < Layout.PanelData.length; i++) {
if (Layout.PanelData[i].key === key) {
return i;
}
}
return undefined;
}
_getLinesFromDescription(text) {
const parts = text.split(' ');
const lines = [];
var line = '';
for (const part of parts) {
if (line.length + part.length <= this.PANEL_CONFIG.WIDTH) {
line += part;
} else {
lines.push(line);
line = new String(part);
}
if (line.length < this.PANEL_CONFIG.WIDTH) {
line += ' ';
}
}
lines.push(line);
return lines;
}
_populatePanel(config) {
if (config.mode === SelectModes.SEARCH) {
this._populateSearchPanel(config);
} else {
this._populateDataPanel(config);
}
}
_populateDataPanel(config) {
// Top
if (config.panel && config.panel.top) {
if (config.panel.top.element) {
this._setTextColor(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.TOP_POS.y, this.PANEL_CONFIG.WIDTH, Colors.FOCUS_GOLD, true);
this._setText(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.TOP_POS.y, config.panel.top.element, this.PANEL_CONFIG.WIDTH, 'center');
} else if (config.panel.top.family) {
const color = this.FAMILIES_CONFIG[config.panel.top.id].color;
this._setTextColor(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.TOP_POS.y, this.PANEL_CONFIG.WIDTH, color, true);
this._setText(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.TOP_POS.y, config.panel.top.family, this.PANEL_CONFIG.WIDTH, 'center');
} else if (config.panel.top.shell) {
const color = this.SHELLS_CONFIG[config.panel.top.id].color;
this._setTextColor(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.TOP_POS.y, this.PANEL_CONFIG.WIDTH, color, true);
this._setText(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.TOP_POS.y, config.panel.top.shell, this.PANEL_CONFIG.WIDTH, 'center');
}
}
// List
if (config.panel.bottom && config.panel.bottom.list) {
var currentY = this.PANEL_CONFIG.LIST_POS.y;
var hasExpected = false;
for (const pair of config.panel.bottom.list) {
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x, currentY, this.PANEL_CONFIG.WIDTH / 2, Colors.GRAY, false);
this._setText(this.PANEL_CONFIG.TOP_POS.x, currentY, pair.key + ':', this.PANEL_CONFIG.WIDTH / 2, 'right');
const value = this._getPanelValue(pair.value);
if (value.length + 1 > this.PANEL_CONFIG.WIDTH / 2) {
currentY++;
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x, currentY, this.PANEL_CONFIG.WIDTH, Colors.WHITE, false);
this._setText(this.PANEL_CONFIG.TOP_POS.x, currentY, ' ' + value, this.PANEL_CONFIG.WIDTH, 'right');
} else {
var color = Colors.WHITE;
if (pair.value === undefined) {
color = Colors.GRAY;
}
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x + (this.PANEL_CONFIG.WIDTH / 2), currentY, this.PANEL_CONFIG.WIDTH / 2, color, false);
this._setText(this.PANEL_CONFIG.TOP_POS.x + (this.PANEL_CONFIG.WIDTH / 2), currentY, ' ' + this._getPanelValue(pair.value), this.PANEL_CONFIG.WIDTH / 2, 'left');
if (value !== undefined && value.endsWith(' **')) {
hasExpected = true;
}
}
currentY++;
}
if (config.displayMode && config.displayMode.key) {
const fieldIndex = this._getFieldIndex(config.displayMode.key);
this._setHighlightColor(this.PANEL_CONFIG.LIST_POS.x - 1, this.PANEL_CONFIG.LIST_POS.y + fieldIndex, this.PANEL_CONFIG.WIDTH + 2, Colors.WHITE);
}
if (hasExpected) {
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x, this.PANEL_CONFIG.LIST_POS.y + this.PANEL_CONFIG.HEIGHT - 1, this.PANEL_CONFIG.WIDTH, Colors.GRAY, false);
this._setText(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.LIST_POS.y + this.PANEL_CONFIG.HEIGHT - 1, '** Expected', this.PANEL_CONFIG.WIDTH, 'right');
}
} else if (config.panel.bottom && config.panel.bottom.description) {
const lines = this._getLinesFromDescription(config.panel.bottom.description);
var currentY = this.PANEL_CONFIG.LIST_POS.y;
for (const line of lines) {
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x, currentY, this.PANEL_CONFIG.WIDTH, Colors.LIGHT_GRAY, false);
this._setText(this.PANEL_CONFIG.TOP_POS.x, currentY, line, this.PANEL_CONFIG.WIDTH, 'left');
currentY++;
}
}
}
_populateSearchPanel(config) {
const hasResults = config.panel.bottom && config.panel.bottom.results && config.panel.bottom.results.length > 0;
// Top
if (config.panel && config.panel.top) {
if (config.panel.top.query) {
const color = hasResults ? this.SEARCH_CONFIG.colors.RESULTS : this.SEARCH_CONFIG.colors.NO_RESULTS;
this._setTextColor(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.TOP_POS.y, this.PANEL_CONFIG.WIDTH, color, true);
this._setText(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.TOP_POS.y, config.panel.top.query, this.PANEL_CONFIG.WIDTH, 'center');
}
}
// Bottom
if (hasResults) {
const highlightLength = config.panel.top.query ? config.panel.top.query.length : 0;
const nameOffset = 5;
if (config.panel.bottom.index !== undefined) {
this._setHighlightColor(this.PANEL_CONFIG.LIST_POS.x - 1, this.PANEL_CONFIG.LIST_POS.y + config.panel.bottom.index, this.PANEL_CONFIG.WIDTH + 2, Colors.WHITE);
}
for (let i = 0; i < config.panel.bottom.results.length; i++) {
const item = config.panel.bottom.results[i];
const isSelected = config.panel.bottom.index === i;
const selectedColor = isSelected ? this.SEARCH_CONFIG.colors.RESULTS_FOCUSED : this.SEARCH_CONFIG.colors.RESULTS;
if (item.type === SearchResultType.ELEMENT) {
if (item.atomicNumber !== undefined) {
this._setText(this.PANEL_CONFIG.LIST_POS.x, this.PANEL_CONFIG.LIST_POS.y + i, item.atomicNumber.text, 3, 'left');
if (item.atomicNumber.index !== undefined) {
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x + item.atomicNumber.index, this.PANEL_CONFIG.LIST_POS.y + i, highlightLength, selectedColor, false);
}
} else if (item.atomicSymbol !== undefined) {
this._setText(this.PANEL_CONFIG.LIST_POS.x, this.PANEL_CONFIG.LIST_POS.y + i, item.atomicSymbol.text, 2, 'left');
if (item.atomicSymbol.index !== undefined) {
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x + item.atomicSymbol.index, this.PANEL_CONFIG.LIST_POS.y + i, highlightLength, selectedColor, false);
}
}
if (item.name) {
this._setText(this.PANEL_CONFIG.LIST_POS.x + nameOffset, this.PANEL_CONFIG.LIST_POS.y + i, item.name.text, this.PANEL_CONFIG.WIDTH - nameOffset, 'left');
if (item.name.index !== undefined) {
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x + item.name.index + nameOffset, this.PANEL_CONFIG.LIST_POS.y + i, highlightLength, selectedColor, false);
}
}
} else {
if (item.name) {
this._setText(this.PANEL_CONFIG.LIST_POS.x, this.PANEL_CONFIG.LIST_POS.y + i, item.name.text, this.PANEL_CONFIG.WIDTH, 'left');
if (item.name.index !== undefined) {
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x + item.name.index, this.PANEL_CONFIG.LIST_POS.y + i, highlightLength, selectedColor, false);
}
}
}
}
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x, this.PANEL_CONFIG.LIST_POS.y + this.PANEL_CONFIG.HEIGHT - 2, this.PANEL_CONFIG.WIDTH, Colors.GRAY, false);
this._setText(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.LIST_POS.y + this.PANEL_CONFIG.HEIGHT - 2, 'Navigation:<UP|DOWN> Select:<ENTER>', this.PANEL_CONFIG.WIDTH, 'center');
} else {
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x, this.PANEL_CONFIG.LIST_POS.y, this.PANEL_CONFIG.WIDTH, Colors.GRAY, false);
this._setText(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.LIST_POS.y, 'NO RESULTS', this.PANEL_CONFIG.WIDTH, 'center');
}
this._setTextColor(this.PANEL_CONFIG.LIST_POS.x, this.PANEL_CONFIG.LIST_POS.y + this.PANEL_CONFIG.HEIGHT - 1, this.PANEL_CONFIG.WIDTH, Colors.GRAY, false);
this._setText(this.PANEL_CONFIG.TOP_POS.x, this.PANEL_CONFIG.LIST_POS.y + this.PANEL_CONFIG.HEIGHT - 1, 'Exit Search:<LEFT>', this.PANEL_CONFIG.WIDTH, 'center');
}
_getPanelValue(value) {
if (value !== undefined) {
if (value === true) {
return 'Yes';
} else if (value === false) {
return 'No';
}
return String(value);
} else {
return '-';
}
}
_getFullScreenBoard() {
const fullRows = process.stdout.rows;
const fullColumns = process.stdout.columns;
const fullBoard = [];
for (var r = 0; r < fullRows; r++) {
const row = [];
for (var c = 0; c < fullColumns; c++) {
row.push({
character: ' ',
config: {
backgroundColor: this.BG_COLOR.BG,
},
});
}
fullBoard.push(row);
}
const rowsToDraw = Math.min(fullRows, this.board.length);
const columnsToDraw = Math.min(fullColumns, this.board[0].length);
for (var r = 0; r < rowsToDraw; r++) {
for (var c = 0; c < columnsToDraw; c++) {
var cOffset = 0;
if (fullColumns > this.board[r].length) {
cOffset = parseInt((fullColumns - this.board[r].length) * this.HORIZONTAL_RATIO);
}
var rOffset = 0;
if (fullRows > this.board.length) {
rOffset = parseInt((fullRows - this.board.length) * this.VERTICAL_RATIO);
}
fullBoard[rOffset + r][cOffset + c] = this.board[r + this.scrolling.y][c + this.scrolling.x];
}
}
return fullBoard;
}
scrollUp() {
const fullRows = process.stdout.rows;
if (fullRows < this.board.length && this.scrolling.y > 0) {
this.scrolling.y -= 1;
return true;
}
return false;
}
scrollDown() {
const fullRows = process.stdout.rows;
if (fullRows < this.board.length && this.scrolling.y + fullRows < this.board.length) {
this.scrolling.y += 1;
return true;
}
return false;
}
scrollLeft() {
const fullColumns = process.stdout.columns;
if (fullColumns < this.board[0].length && this.scrolling.x > 0) {
this.scrolling.x -= 1;
return true;
}
return false;
}
scrollRight() {
const fullColumns = process.stdout.columns;
if (fullColumns < this.board[0].length && this.scrolling.x + fullColumns < this.board[0].length) {
this.scrolling.x += 1;
return true;
}
return false;
}
updateScrollingOnResize() {
const fullRows = process.stdout.rows;
const fullColumns = process.stdout.columns;
if (this.scrolling.y + fullRows > this.board.length) {
this.scrolling.y = Math.max(this.board.length - fullRows, 0);
}
if (this.scrolling.x + fullColumns > this.board[0].length) {
this.scrolling.x = Math.max(this.board[0].length - fullColumns, 0);
}
}
_draw() {
const fullBoard = this._getFullScreenBoard();
return Renderer.generateOptimized(fullBoard);
}
render(config) {
this._resetBoard();
this._setBackground();
this._decorateTitles();
this._setDisplayMode(config);
this._applyConfigToElements(config);
this._populatePanel(config);
return this._draw();
}
}
module.exports = {
Dashboard: Dashboard,
}