class FSMDocument { constructor(name) { this.id = guid(); this.name = null; this.createdAt = Date.now(); this.lastModified = Date.now(); this.element = null; this.unsaved = true; this.lastSavedHash = ''; this.states = []; this.connections = []; } tick() { this.states.forEach(stateA => { this.states.forEach(stateB => { if (stateA !== stateB && stateA.intersects(stateB)) { const inter = stateA.intersection(stateB); const angle1 = stateA.directionTo(stateB); const angle2 = angle1 + Math.PI; const x1 = Math.cos(angle1) * inter + stateA.x; const y1 = Math.sin(angle1) * inter + stateA.y; const x2 = Math.cos(angle2) * inter + stateB.x; const y2 = Math.sin(angle2) * inter + stateB.y; stateA.moveTo(x1, y1); stateB.moveTo(x2, y2); } }); }); this.states.forEach(state => { if (state.v) { state.moveToStep(); } }); if(!this.unsaved) { if(this.hashCode() !== this.lastSavedHash) { this.unsaved = true; this.element.classList.add('unsaved'); } } } draw() { this.states.forEach(state => state.draw()); this.connections.forEach(connection => connection.draw()); } onDblClick(x, y) { if (!selectedObject) { selectedObject = new State(x, y); this.states.push(selectedObject); resetCaret(); } else if (selectedObject instanceof State) { selectedObject.isAcceptState = !selectedObject.isAcceptState; } } onRightClick(x, y) { if(!selectedObject) { } } deleteCurrentObject() { if (!!selectedObject) { if (selectedObject instanceof State) { this.states.splice(this.states.findIndex(state => state === selectedObject), 1); } for (let i = 0; i < this.connections.length; i++) { const con = this.connections[i]; if (con === selectedObject || con.state === selectedObject || con.stateA === selectedObject || con.stateB === selectedObject) { this.connections.splice(i--, 1); } } selectedObject = null; } } }