diff --git a/heartbeat.webm b/heartbeat.webm
new file mode 100644
index 0000000..798aa98
Binary files /dev/null and b/heartbeat.webm differ
diff --git a/index.template.html b/index.template.html
index 3b7a443..2e8aa3a 100644
--- a/index.template.html
+++ b/index.template.html
@@ -3,9 +3,20 @@
+
MEDTRACE: Case - Frontend Developer
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ECGTicker/ECGTicker.ts b/src/ECGTicker/ECGTicker.ts
index a299f91..59e87b4 100644
--- a/src/ECGTicker/ECGTicker.ts
+++ b/src/ECGTicker/ECGTicker.ts
@@ -1,22 +1,26 @@
-const template = document.getElementById("my-card-template") as
+import * as THREE from "three";
+import {OrbitControls} from "three/addons/controls/OrbitControls.js";
+
+
+const template = document.getElementById("ecg-ticker-template") as
HTMLTemplateElement;
enum Attributes {
- MESSAGE = "message",
+ HEART_RATE = "heart-rate",
}
export default class ECGTicker extends HTMLElement {
- static observedAttributes = [Attributes.MESSAGE];
+ static observedAttributes = [Attributes.HEART_RATE];
private _content: DocumentFragment;
- $message: HTMLElement;
+ $canvasContainer: HTMLElement;
constructor() {
super();
this.attachShadow({mode: "open"});
this._content = template.content.cloneNode(true) as DocumentFragment;
- this.$message = this._content.getElementById("message")!;
+ this.$canvasContainer = this._content.getElementById("canvas-container")!;
}
connectedCallback() {
@@ -25,18 +29,73 @@ export default class ECGTicker extends HTMLElement {
} else {
console.warn("No shadowRoot detected.");
}
+
+ this.initECGAnimation();
+ }
+
+ initECGAnimation() {
+ const renderer = new THREE.WebGLRenderer();
+
+ renderer.setSize(200, 300);
+ this.$canvasContainer.appendChild(renderer.domElement);
+
+ const scene = new THREE.Scene();
+
+ const axesHelper = new THREE.AxesHelper(5);
+ scene.add(axesHelper);
+
+ const camera = new THREE.PerspectiveCamera(
+ 75,
+ window.innerWidth / window.innerHeight,
+ 0.1,
+ 1000
+ );
+ const orbit = new OrbitControls(camera, renderer.domElement);
+
+ camera.position.set(1, 2, 5);
+ orbit.update();
+
+ const boxGeometry = new THREE.BoxGeometry(1, 1, 1);
+ const boxMaterial = new THREE.MeshBasicMaterial({color: 0xffff00});
+ const box = new THREE.Mesh(boxGeometry, boxMaterial);
+ scene.add(box);
+
+ let heart_amp = 0.0;
+
+ function animate(x) {
+ let sr = 120;
+ let freq = 20;
+
+ box.position.x = 0.01 * Math.sin(2 * Math.PI * freq * (x / sr));
+ box.position.y = 0.02 * Math.sin(2 * Math.PI * (freq/2) * (x / sr));
+ // box.position.z = 0.05 * Math.sin(2 * Math.PI * (freq/3) * (x / sr));
+ box.position.z = heart_amp * 1;
+ box.rotation.set(x/2000, x/2000, 0);
+ // camera.position.x = 1 * Math.sin(2 * Math.PI * (freq/6) * (x / sr));
+ // camera.position.y = 2 * Math.sin(2 * Math.PI * (freq/11) * (x / sr));
+ // camera.position.z = 1 + Math.abs(15 * Math.sin(2 * Math.PI * (freq/75) * (x / sr)));
+
+ renderer.render(scene, camera);
+ }
+
+ // const socket = new WebSocket(`${location.protocol === "https" ? "wss" : "ws"}://${location.hostname}:7890/ecg`);
+ const socket = new WebSocket(`ws://localhost:7890/ecg`);
+ socket.onmessage = (({data}) => {
+ heart_amp = data;
+ console.log(heart_amp);
+
+ });
+
+ renderer.setAnimationLoop(animate);
}
attributeChangedCallback(name: string, _prev: string, curr: string) {
- if (Attributes.MESSAGE === name) {
- while (this.$message.firstChild) {
- this.$message.removeChild(this.$message.lastChild!);
- }
- this.$message.appendChild(document.createTextNode(curr));
+ if (Attributes.HEART_RATE === name) {
+ // send message via websocket to alter heart rate in real time
}
}
};
-window.customElements.define("x-ecg-ticker", ECGTicker);
+window.customElements.define("ecg-ticker", ECGTicker);
export {};
\ No newline at end of file
diff --git a/src/MyCard/MyCard.html b/src/MyCard/MyCard.html
index 0f504e2..c667d7c 100644
--- a/src/MyCard/MyCard.html
+++ b/src/MyCard/MyCard.html
@@ -22,7 +22,7 @@
}
header h1 {
- font-size: 1.75rem;
+ font-size: 1.4rem;
}
#message {
margin: 15px;