diff --git a/README.md b/README.md
index 0ede108..09d17d8 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,8 @@ The repl has the following syntax (It's work in progress, new capabilities will
```vector(-1 -1)``` != ```vector(-1-1)``` and the latter would mean ```vector(-2)``` which is not legal.
* arrays: \[i0, i1, i2, ... in] creates an array.
* \[i0, i1] is special: it is a shorthand for creating a 2-dimensional vector. I'll have to think of another way to create an array of length 2...
-
+
+* ```id()`` adds a 2d identity matrix, which is also the two basis vectors.
* properties
* ```a = [1,2]```
* ```a.type```
diff --git a/src/css/app.css b/src/css/app.css
index 6607311..7db77eb 100644
--- a/src/css/app.css
+++ b/src/css/app.css
@@ -4,11 +4,13 @@ body {
overflow: hidden;
}
-.right{
+
+.right {
color: gray;
position: absolute;
right: 0;
}
+
.background {
position: absolute;
left: 0;
@@ -51,6 +53,15 @@ svg {
z-index: 10;
}
+#slider {
+ position: absolute;
+ left: calc(50% - 1.5em);
+ top: -1em;
+ color: darkgray;
+ cursor: row-resize;
+ user-select: none;
+}
+
.axis {
stroke-width: 1.5;
stroke: lightpink;
@@ -62,12 +73,25 @@ svg {
stroke-linecap: round;
}
-#prompt{
+.matrix {
+ stroke-width: 2.5;
+ stroke-linecap: round;
+}
+
+.matrix.i {
+ stroke: green;
+}
+
+.matrix.j {
+ stroke: red;
+}
+
+#prompt {
position: absolute;
bottom: 0;
}
-.multiline{
+.multiline {
border-top: 1px slategray solid;
border-left: 1px slategray solid;
border-right: 1px slategray solid;
@@ -76,11 +100,11 @@ svg {
border-top-right-radius: 3px;
}
-.single_line{
+.single_line {
border: none transparent;
}
-#command_input{
+#command_input {
background: #111;
color: greenyellow;
outline: none;
@@ -88,7 +112,7 @@ svg {
height: 1em;
}
-#command_history{
+#command_history {
font-size: 12px;
color: greenyellow;
position: absolute;
diff --git a/src/index.html b/src/index.html
index 45995ca..dc6f982 100644
--- a/src/index.html
+++ b/src/index.html
@@ -7,6 +7,7 @@
+
___
diff --git a/src/js/functions.js b/src/js/functions.js
index 3870467..1dd6034 100644
--- a/src/js/functions.js
+++ b/src/js/functions.js
@@ -11,6 +11,9 @@ export const functions = {
return create_vector(args[0], args[1], args[2], args[3]);
}
},
+ id: () => {
+ return create_2d_id_matrix()
+ },
hide: (args) => {
return hide(args[0]);
},
@@ -103,7 +106,8 @@ export const create_vector = function (x0, y0, x, y) { //rename to create_vector
return show(this);
},
equals: function (other) {
- return (this.id === other.id || (this.x0 === other.x0 && this.y0 === other.y0 && this.x === other.x && this.y === other.y));
+ return (this.id === other.id ||
+ (this.type === other.type && this.x0 === other.x0 && this.y0 === other.y0 && this.x === other.x && this.y === other.y));
}
};
return vector;
@@ -171,4 +175,36 @@ export const logical_and = function (left, right) {
export const logical_or = function (left, right) {
return left || right;
+}
+
+const create_2d_id_matrix = function () {
+ return {
+ data: [[1, 0], [0, 1]],
+ id: index_sequence++,
+ is_visual: true,
+ is_vector: false, // for type comparison
+ is_matrix: true,
+ type: 'matrix', // for showing type to user
+ is_new: true, // to determine view action
+ visible: true,
+ toString: function () {
+ return `matrix@${this.id}`;
+ },
+ hide: function () {
+ return hide(this);
+ },
+ label: function (text) {
+ return label(this, text);
+ },
+ show: function () {
+ return show(this);
+ },
+ equals: function (other) {
+ return (this.id === other.id || (this.type === other.type && this.data === other.data)); // TODO
+ },
+ row: function (index) {
+ return this.data[index];
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/js/index.js b/src/js/index.js
index 171be55..28f8ce0 100644
--- a/src/js/index.js
+++ b/src/js/index.js
@@ -1,7 +1,7 @@
import '../css/app.css';
import {scan, token_types} from './scanner';
import {parse} from './parser';
-import {add_vector_arrow, add_vector_arrow_to_svg, update_vector_arrow} from "./svg_functions";
+import {add_matrix_view, add_vector_arrow, add_vector_arrow_to_svg, update_vector_arrow,} from "./svg_functions";
import {
addition,
create_vector,
@@ -97,6 +97,9 @@ command_input_element.onkeypress = function handle_key_input(event) {
command_input_element.onkeyup = function handle_key_input(event) {
adjust_input_element_height();
+ if (event.key === 'c' && event.ctrlKey) {
+ command_input_element.value = '';
+ }
if (event.key === 'ArrowUp' && !event.shiftKey) {
if (command_history_index > -1) {
command_input_element.value = command_history[command_history_index];
@@ -151,14 +154,10 @@ const handle_enter = function () {
}
if (value.is_visual) {
- if (binding && bindings[binding].previous && bindings[binding].previous.is_visual) {
- update_vector_arrow(bindings[binding].previous.id, value);
- } else {
- if (value.is_new) {
- value.label_text = binding ? binding : "";
- value.is_new = false;
- add_vector_arrow(value);
- }
+ if (value.is_vector) {
+ create_or_update_vector(binding, value);
+ } else if (value.is_matrix) {
+ create_or_update_matrix(binding, value);
}
} else {
if (binding && bindings[binding].previous && bindings[binding].previous.is_visual) {
@@ -323,4 +322,28 @@ const resolve_arguments = function (argument_exprs) {
}
return value;
});
+}
+
+function create_or_update_vector(binding, value) {
+ if (binding && bindings[binding].previous && bindings[binding].previous.is_visual) {
+ update_vector_arrow(bindings[binding].previous.id, value);
+ } else {
+ if (value.is_new) {
+ value.label_text = binding ? binding : "";
+ value.is_new = false;
+ add_vector_arrow(value);
+ }
+ }
+}
+
+function create_or_update_matrix(binding, value) {
+ if (binding && bindings[binding].previous && bindings[binding].previous.is_visual) {
+ // update_matrix_view(bindings[binding].previous.id, value);
+ } else {
+ if (value.is_new) {
+ value.label_text = binding ? binding : "";
+ value.is_new = false;
+ add_matrix_view(value);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/js/svg_functions.js b/src/js/svg_functions.js
index 75be431..fbbb133 100644
--- a/src/js/svg_functions.js
+++ b/src/js/svg_functions.js
@@ -1,15 +1,17 @@
import {update_visible_objects} from "./index";
let vectors_by_id = {};
+let matrices_by_id = {};
const SVG_NS = 'http://www.w3.org/2000/svg'; // program needs these to create svg elements
let grid_size = 100; // this is the nr of pixels for the basis vector (1,0) (0,1)
let half_grid_size = grid_size >> 1; // used to position the grid lines
-
+const slider = document.getElementById('slider');
+const console_element = document.getElementById('console');
let moving_vector; // user can move vector arrows. when moving, this refers to the arrow
-let width = window.innerWidth, height = window.innerHeight;
-let origin_x = Math.floor((width / grid_size) / 2) * grid_size + half_grid_size,
- origin_y = Math.floor((height / grid_size) / 2) * grid_size + half_grid_size;
-
+let window_width = window.innerWidth, window_height = window.innerHeight;
+let origin_x = Math.floor((window_width / grid_size) / 2) * grid_size + half_grid_size,
+ origin_y = Math.floor((window_height / grid_size) / 2) * grid_size + half_grid_size;
+let slider_start_Y, slider_start_height;
/**
* Creates an svg element
* @param element_type path,g, etc
@@ -89,15 +91,16 @@ const create_line = function (x0, y0, x1, y1, css_class) {
* @param x1 end_x
* @param y1 end_y
* @param css_class class attribute
+ * @param arrow_def SVG definition of the arrow head
* @returns {SVGPathElement}
*/
-const create_arrow = function (id, x0, y0, x1, y1, css_class) {
+const create_arrow = function (id, x0, y0, x1, y1, css_class, arrow_def) {
let path = create_svg_element('path');
path.setAttribute('d', calculate_d(x0, y0, x1, y1));
path.id = id;
path.setAttribute('class', css_class);
- path.setAttribute('marker-end', 'url(#arrow)');
+ path.setAttribute('marker-end', arrow_def);
return path;
}
@@ -118,31 +121,27 @@ export const create_grid = function (css_class, bg_css_class) {
group.setAttribute('id', 'grid');
const horizontal = create_svg_element('g');
horizontal.setAttribute('id', 'horizontal');
- for (let y = 0; y < height; y += grid_size) {
- horizontal.appendChild(create_line(0, y + half_grid_size, width, y + half_grid_size, css_class));
- horizontal.appendChild(create_line(0, y, width, y, bg_css_class));
+ for (let y = 0; y < window_height; y += grid_size) {
+ horizontal.appendChild(create_line(0, y + half_grid_size, window_width, y + half_grid_size, css_class));
+ horizontal.appendChild(create_line(0, y, window_width, y, bg_css_class));
}
group.appendChild(horizontal);
const vertical = create_svg_element('g');
vertical.setAttribute('id', 'vertical');
- for (let x = 0; x < width; x += grid_size) {
- vertical.appendChild(create_line(x + half_grid_size, 0, x + half_grid_size, height, css_class));
- vertical.appendChild(create_line(x, 0, x, height, bg_css_class));
+ for (let x = 0; x < window_width; x += grid_size) {
+ vertical.appendChild(create_line(x + half_grid_size, 0, x + half_grid_size, window_height, css_class));
+ vertical.appendChild(create_line(x, 0, x, window_height, bg_css_class));
}
group.appendChild(vertical);
return group;
}
-export const add_vector_arrow = function (vector) {
- vectors_by_id[vector.id] = vector;
- add_vector_arrow_to_svg(vector);
-}
-function create_label(vector) {
+function create_label(vector, color) {
let label = create_svg_element('text');
- label.setAttribute('x', (calc_screen_x(vector.x) + 5).toString());
- label.setAttribute('y', (calc_screen_y(vector.y) + 5).toString());
- label.setAttribute('fill', 'yellow');
+ label.setAttribute('x', (calc_screen_x(vector.x) - 5).toString());
+ label.setAttribute('y', (calc_screen_y(vector.y) + 15).toString());
+ label.setAttribute('fill', color);
label.setAttribute('id', 'l' + vector.id);
let text_node = document.createTextNode(vector.label_text);
label.appendChild(text_node);
@@ -163,26 +162,49 @@ export const update_label_text = function (id, text) {
}
}
-
export const add_vector_arrow_to_svg = function (vector) {
let vector_group = get_or_create_vector_group();
- let vector_arrow = create_arrow(vector.id, vector.x0, vector.y0, vector.x, vector.y, 'vector');
+ let vector_arrow = create_arrow(vector.id, vector.x0, vector.y0, vector.x, vector.y, 'vector', 'url(#vector_arrow)');
vector_arrow.onmousedown = function start_moving_vector(event) {
moving_vector = event.target;
+
+ window.onmousemove = move;
+
+ window.onmouseup = function () {
+ window.onmousemove = undefined;
+ window.onmouseup = undefined;
+ };
};
vector_group.appendChild(vector_arrow);
- let label = create_label(vector);
+ let label = create_label(vector, 'yellow');
vector_group.appendChild(label);
}
+export const add_matrix_to_svg = function (matrix) {
+ let matricesGroup = get_or_create_matrices_group();
+ let vector_arrow_i = create_arrow(matrix.id, 0, 0, matrix.row(0)[0], matrix.row(0)[1], 'matrix i', 'url(#matrix_i_arrow)');
+ let vector_arrow_j = create_arrow(matrix.id, 0, 0, matrix.row(1)[0], matrix.row(1)[1], 'matrix j', 'url(#matrix_j_arrow)');
+ matricesGroup.appendChild(vector_arrow_i);
+ matricesGroup.appendChild(vector_arrow_j);
+
+ matricesGroup.appendChild(create_label({
+ x: matrix.row(0)[0],
+ y: matrix.row(0)[1],
+ id: matrix.id + "i",
+ label_text: 'i'
+ }, 'green'));
+ matricesGroup.appendChild(create_label({
+ x: matrix.row(1)[0],
+ y: matrix.row(1)[1],
+ id: matrix.id + "j",
+ label_text: 'j'
+ }, 'red'));
+}
+
+
/**
* Draws all the vectors.
- *
- * vector {
- * x0,y0 origin
- * x,y coordinates
- * }
*/
const draw_vectors = function () {
const vector_group = get_or_create_vector_group();
@@ -196,6 +218,21 @@ const draw_vectors = function () {
svg.appendChild(vector_group);
}
+/**
+ * Draws all the matrices.
+ */
+const draw_matrices = function () {
+ const matrices_group = get_or_create_matrices_group();
+
+ let matrices = Object.values(matrices_by_id);
+ for (let i = 0; i < matrices.length; i++) {
+ if (matrices[i].visible) {
+ add_matrix_to_svg(matrices[i]);
+ }
+ }
+ svg.appendChild(matrices_group);
+}
+
const get_or_create_vector_group = function () {
let vector_group = document.getElementById('vectors');
if (vector_group === null || vector_group === undefined) {
@@ -207,6 +244,17 @@ const get_or_create_vector_group = function () {
return vector_group;
}
+const get_or_create_matrices_group = function () {
+ let matrices_group = document.getElementById('matrices');
+ if (matrices_group === null || matrices_group === undefined) {
+ matrices_group = create_svg_element("g");
+ svg.appendChild(matrices_group);
+ matrices_group.id = 'matrices';
+ }
+
+ return matrices_group;
+}
+
/**
* Removes all vectors in the svg and calls draw_vectors to draw updated versions.
*/
@@ -214,6 +262,14 @@ const redraw_vectors = function () {
remove_child(svg, 'vectors');
draw_vectors();
}
+
+/**
+ * Removes all vectors in the svg and calls draw_vectors to draw updated versions.
+ */
+const redraw_matrices = function () {
+ remove_child(svg, 'matrices');
+ draw_matrices();
+}
/**
* removes the grid from the DOM and adds an updated one.
*/
@@ -244,15 +300,16 @@ export const update_vector_arrow = function (existing_id, new_vector) {
export const redraw = function () {
redraw_grid();
redraw_vectors();
+ redraw_matrices();
}
const create_axes = function () {
let axes_group = create_svg_element('g');
axes_group.setAttribute('id', 'axes');
- let x = create_line(0, origin_y, width, origin_y, 'axis');
+ let x = create_line(0, origin_y, window_width, origin_y, 'axis');
x.id = 'x-axis';
axes_group.appendChild(x);
- let y = create_line(origin_x, 0, origin_x, height, 'axis');
+ let y = create_line(origin_x, 0, origin_x, window_height, 'axis');
y.id = 'y-axis';
axes_group.appendChild(y);
return axes_group;
@@ -262,10 +319,10 @@ const create_axes = function () {
* setup the arrow head for the vector
* @returns {SVGDefsElement}
*/
-const create_defs = function () {
+const create_defs = function (type, color) {
let defs = create_svg_element('defs');
let marker = create_svg_element('marker');
- marker.id = 'arrow';
+ marker.id = type;
marker.setAttribute('orient', 'auto');
marker.setAttribute('viewBox', '0 0 10 10');
marker.setAttribute('markerWidth', '3');
@@ -275,30 +332,25 @@ const create_defs = function () {
marker.setAttribute('refY', '5');
let polyline = create_svg_element('polyline');
polyline.setAttribute('points', '0,0 10,5 0,10 1,5');
- polyline.setAttribute('fill', 'yellow');
+ polyline.setAttribute('fill', color);
marker.appendChild(polyline);
defs.appendChild(marker);
return defs;
}
-/**
- * The moving operation. Called by onmousemove on the svg ('canvas')
- * @param event
- */
-const move_vector = function (event) {
- if (moving_vector) {
- let current_x = event.offsetX;
- let current_y = event.offsetY;
- let vector = vectors_by_id[parseInt(moving_vector.id)];
- if (vector) {
- vector.x = (current_x - origin_x) / grid_size;
- vector.y = (origin_y - current_y) / grid_size;
- moving_vector.setAttribute('d', create_d(origin_x, origin_y, current_x, current_y));
- update_label(moving_vector.id, moving_vector.id, current_x + 5, current_y + 5);
- update_visible_objects();
- }
+const move = function (event) {
+ let current_x = event.offsetX;
+ let current_y = event.offsetY;
+ let vector = vectors_by_id[parseInt(moving_vector.id)];
+ if (vector) {
+ vector.x = (current_x - origin_x) / grid_size;
+ vector.y = (origin_y - current_y) / grid_size;
+ moving_vector.setAttribute('d', create_d(origin_x, origin_y, current_x, current_y));
+ update_label(moving_vector.id, moving_vector.id, current_x + 5, current_y + 5);
+ update_visible_objects();
}
}
+
/**
* Creates the SVG
* @returns {SVGElement}
@@ -306,21 +358,32 @@ const move_vector = function (event) {
const create_svg = function () {
let svg = create_svg_element('svg');
- svg.onmousemove = move_vector;
- svg.onmouseup = function stop_moving_vector() {
+ svg.onmousemove = move;
+ svg.onmouseup = function stop_moving() {
moving_vector = undefined;
};
- let defs = create_defs();
- svg.appendChild(defs);
+ svg.appendChild(create_defs('vector_arrow', 'yellow'));
+ svg.appendChild(create_defs('matrix_i_arrow', 'green'));
+ svg.appendChild(create_defs('matrix_j_arrow', 'red'));
return svg;
}
+export const add_vector_arrow = function (vector) {
+ vectors_by_id[vector.id] = vector;
+ add_vector_arrow_to_svg(vector);
+}
+
+export const add_matrix_view = function (matrix) {
+ matrices_by_id[matrix.id] = matrix;
+ add_matrix_to_svg(matrix);
+}
+
document.body.onresize = function recalculate_window_dimensions() {
- width = window.innerWidth;
- height = window.innerHeight;
- origin_x = Math.floor((width / grid_size) / 2) * grid_size + half_grid_size;
- origin_y = Math.floor((height / grid_size) / 2) * grid_size + half_grid_size;
+ window_width = window.innerWidth;
+ window_height = window.innerHeight;
+ origin_x = Math.floor((window_width / grid_size) / 2) * grid_size + half_grid_size;
+ origin_y = Math.floor((window_height / grid_size) / 2) * grid_size + half_grid_size;
redraw();
}
@@ -329,3 +392,18 @@ document.body.appendChild(svg);
svg.appendChild(create_grid('grid', 'bg-grid'));
svg.appendChild(create_axes());
get_or_create_vector_group();
+get_or_create_matrices_group();
+
+slider.onmousedown = function (event) {
+ slider_start_Y = event.clientY;
+ slider_start_height = parseInt(document.defaultView.getComputedStyle(console_element).height, 10);
+
+ window.onmousemove = function (event) {
+ console_element.style.height = (slider_start_height - (event.clientY - slider_start_Y)) + 'px';
+ }
+
+ window.onmouseup = function () {
+ window.onmousemove = undefined;
+ window.onmouseup = undefined;
+ };
+};