broadfield-dev commited on
Commit
39d7539
·
verified ·
1 Parent(s): 2b890a2

Update static/canvas.js

Browse files
Files changed (1) hide show
  1. static/canvas.js +176 -104
static/canvas.js CHANGED
@@ -1,21 +1,29 @@
 
 
 
 
1
  const stage = new Konva.Stage({
2
  container: 'container',
3
- width: window.innerWidth - 350,
4
- height: window.innerHeight,
5
  draggable: true
6
  });
7
 
8
  const layer = new Konva.Layer();
9
  stage.add(layer);
10
 
 
11
  let scale = 1;
 
 
12
  stage.on('wheel', (e) => {
13
  e.evt.preventDefault();
14
  const oldScale = stage.scaleX();
15
  const pointer = stage.getPointerPosition();
16
- const scaleBy = 1.1;
17
  const newScale = e.evt.deltaY > 0 ? oldScale / scaleBy : oldScale * scaleBy;
18
  stage.scale({ x: newScale, y: newScale });
 
19
  const newPos = {
20
  x: pointer.x - (pointer.x - stage.x()) / oldScale * newScale,
21
  y: pointer.y - (pointer.y - stage.y()) / oldScale * newScale
@@ -23,8 +31,25 @@ stage.on('wheel', (e) => {
23
  stage.position(newPos);
24
  });
25
 
26
- function parseCode() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  const code = document.getElementById('codeInput').value;
 
 
28
  fetch('/parse', {
29
  method: 'POST',
30
  headers: { 'Content-Type': 'application/json' },
@@ -32,127 +57,174 @@ function parseCode() {
32
  })
33
  .then(res => res.json())
34
  .then(data => {
35
- drawGraph(data);
36
- document.getElementById('stats').innerHTML = `Nodes: ${data.nodes.length}<br>Generated Vectors: ${data.nodes.length}`;
37
- });
38
- }
 
 
 
 
 
39
 
40
- function exportDataset() {
41
  const code = document.getElementById('codeInput').value;
42
- fetch('/generate_dataset', {
 
 
43
  method: 'POST',
44
  headers: { 'Content-Type': 'application/json' },
45
  body: JSON.stringify({ code: code })
46
  })
47
  .then(res => res.json())
48
- .then(data => alert(`Dataset entry created at: ${data.path}`));
49
- }
 
 
 
 
 
 
50
 
 
51
  function drawGraph(data) {
52
  layer.destroyChildren();
53
 
 
 
54
  const nodeMap = {};
55
- const startX = 50;
56
- const startY = 50;
57
-
58
- // Auto-Layout Logic: Indent based on 'level'
59
- data.nodes.forEach((n, i) => {
60
- const x = startX + (n.level * 60);
61
- const y = startY + (i * 90);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- const grp = createNodeGroup(x, y, n);
64
- layer.add(grp);
65
- nodeMap[n.id] = { grp, x, y, ...n };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  });
67
 
68
- // Draw Connections
69
  data.connections.forEach(conn => {
70
- const from = nodeMap[conn.from];
71
- const to = nodeMap[conn.to];
72
- if (from && to) {
73
- const arrow = new Konva.Arrow({
74
- points: [from.x + 100, from.y + 25, to.x, to.y + 25],
75
- pointerLength: 6,
76
- pointerWidth: 6,
77
- fill: '#555',
78
- stroke: '#555',
79
- strokeWidth: 2,
80
- tension: 0.4
81
- });
82
- layer.add(arrow);
83
- arrow.moveToBottom();
84
- }
85
- });
86
 
87
- layer.draw();
88
- }
 
 
 
 
89
 
90
- function createNodeGroup(x, y, data) {
91
- const group = new Konva.Group({ x, y, draggable: true });
92
-
93
- // Color mapping
94
- const colors = {
95
- 'function': '#C586C0', // Purple
96
- 'if': '#CE9178', // Orange/Brown
97
- 'for': '#CE9178',
98
- 'assigned_variable': '#9CDCFE', // Blue
99
- 'return': '#569CD6', // Dark Blue
100
- 'other': '#4EC9B0' // Teal
101
- };
102
- const color = colors[data.type] || '#CCCCCC';
103
-
104
- const rect = new Konva.Rect({
105
- width: 180,
106
- height: 50,
107
- fill: '#252526',
108
- stroke: color,
109
- strokeWidth: 2,
110
- cornerRadius: 6,
111
- shadowColor: 'black',
112
- shadowBlur: 10,
113
- shadowOpacity: 0.3
114
- });
115
 
116
- const label = new Konva.Text({
117
- x: 10, y: 10,
118
- text: data.label,
119
- fontSize: 14,
120
- fontFamily: 'JetBrains Mono',
121
- fill: '#ffffff',
122
- width: 160,
123
- ellipsis: true
124
- });
125
-
126
- const subLabel = new Konva.Text({
127
- x: 10, y: 30,
128
- text: `Vec: [${data.vector[0]}, ${data.vector[1]}...]`,
129
- fontSize: 10,
130
- fontFamily: 'JetBrains Mono',
131
- fill: '#888',
132
- width: 160
133
- });
134
 
135
- group.add(rect);
136
- group.add(label);
137
- group.add(subLabel);
138
-
139
- // Add tooltip on hover
140
- group.on('mouseover', () => {
141
- document.body.style.cursor = 'pointer';
142
- rect.stroke('#fff');
143
- layer.draw();
144
- });
145
-
146
- group.on('mouseout', () => {
147
- document.body.style.cursor = 'default';
148
- rect.stroke(color);
149
- layer.draw();
150
  });
151
 
152
- return group;
 
 
 
 
 
 
 
153
  }
154
 
155
- window.addEventListener('resize', () => {
156
- stage.width(window.innerWidth - 350);
157
- stage.height(window.innerHeight);
158
- });
 
1
+ // Initialization
2
+ const width = window.innerWidth - 400; // Subtract sidebar width
3
+ const height = window.innerHeight;
4
+
5
  const stage = new Konva.Stage({
6
  container: 'container',
7
+ width: width,
8
+ height: height,
9
  draggable: true
10
  });
11
 
12
  const layer = new Konva.Layer();
13
  stage.add(layer);
14
 
15
+ // State
16
  let scale = 1;
17
+
18
+ // Zoom Handler
19
  stage.on('wheel', (e) => {
20
  e.evt.preventDefault();
21
  const oldScale = stage.scaleX();
22
  const pointer = stage.getPointerPosition();
23
+ const scaleBy = 1.05;
24
  const newScale = e.evt.deltaY > 0 ? oldScale / scaleBy : oldScale * scaleBy;
25
  stage.scale({ x: newScale, y: newScale });
26
+
27
  const newPos = {
28
  x: pointer.x - (pointer.x - stage.x()) / oldScale * newScale,
29
  y: pointer.y - (pointer.y - stage.y()) / oldScale * newScale
 
31
  stage.position(newPos);
32
  });
33
 
34
+ // Resize Handler
35
+ window.addEventListener('resize', () => {
36
+ stage.width(window.innerWidth - 400);
37
+ stage.height(window.innerHeight);
38
+ });
39
+
40
+ // Logger
41
+ function log(msg, type='info') {
42
+ const consoleBody = document.getElementById('logOutput');
43
+ const color = type === 'error' ? '#ff7675' : '#55efc4';
44
+ consoleBody.innerHTML += `<div style="color:${color}">> ${msg}</div>`;
45
+ consoleBody.scrollTop = consoleBody.scrollHeight;
46
+ }
47
+
48
+ // API Calls
49
+ document.getElementById('btnVisualize').addEventListener('click', () => {
50
  const code = document.getElementById('codeInput').value;
51
+ log('Parsing code structure...');
52
+
53
  fetch('/parse', {
54
  method: 'POST',
55
  headers: { 'Content-Type': 'application/json' },
 
57
  })
58
  .then(res => res.json())
59
  .then(data => {
60
+ if(data.error) {
61
+ log(data.error, 'error');
62
+ } else {
63
+ drawGraph(data);
64
+ log(`Graph generated: ${data.nodes.length} nodes, ${data.connections.length} edges.`);
65
+ }
66
+ })
67
+ .catch(err => log('Network error', 'error'));
68
+ });
69
 
70
+ document.getElementById('btnDataset').addEventListener('click', () => {
71
  const code = document.getElementById('codeInput').value;
72
+ log('Generating vector dataset entry...');
73
+
74
+ fetch('/add_to_dataset', {
75
  method: 'POST',
76
  headers: { 'Content-Type': 'application/json' },
77
  body: JSON.stringify({ code: code })
78
  })
79
  .then(res => res.json())
80
+ .then(data => {
81
+ if(data.status === 'success') {
82
+ log(`Dataset updated. ID: ${data.entry_id}`);
83
+ } else {
84
+ log(data.message, 'error');
85
+ }
86
+ });
87
+ });
88
 
89
+ // Drawing Logic
90
  function drawGraph(data) {
91
  layer.destroyChildren();
92
 
93
+ if (data.nodes.length === 0) return;
94
+
95
  const nodeMap = {};
96
+ const X_OFFSET = 100;
97
+ const Y_START = 50;
98
+ const INDENT_WIDTH = 60;
99
+ const ROW_HEIGHT = 80;
100
+
101
+ // Node Colors based on Category
102
+ const colors = {
103
+ 'function': '#a29bfe', // Purple
104
+ 'class': '#e84393', // Pink
105
+ 'if': '#fab1a0', // Peach
106
+ 'for': '#fdcb6e', // Yellow
107
+ 'while': '#fdcb6e',
108
+ 'return': '#55efc4', // Green
109
+ 'assigned_variable': '#74b9ff', // Blue
110
+ 'import': '#b2bec3' // Grey
111
+ };
112
+
113
+ // Draw Nodes
114
+ data.nodes.forEach((node, index) => {
115
+ // Layout: Simple Waterfall with Indentation
116
+ const x = X_OFFSET + (node.level * INDENT_WIDTH);
117
+ const y = Y_START + (index * ROW_HEIGHT);
118
+
119
+ const group = new Konva.Group({
120
+ x: x,
121
+ y: y,
122
+ draggable: false // Keep rigid for structure visualization
123
+ });
124
+
125
+ // Box
126
+ const rect = new Konva.Rect({
127
+ width: 200,
128
+ height: 50,
129
+ fill: '#2d3436',
130
+ stroke: colors[node.type] || '#636e72',
131
+ strokeWidth: 2,
132
+ cornerRadius: 8,
133
+ shadowColor: 'black',
134
+ shadowBlur: 10,
135
+ shadowOpacity: 0.3
136
+ });
137
+
138
+ // Label
139
+ const text = new Konva.Text({
140
+ x: 10,
141
+ y: 10,
142
+ text: node.label,
143
+ fontSize: 14,
144
+ fontFamily: 'JetBrains Mono',
145
+ fill: '#fff',
146
+ width: 180,
147
+ ellipsis: true
148
+ });
149
+
150
+ // Vector Info (Mini UI)
151
+ const vecText = new Konva.Text({
152
+ x: 10,
153
+ y: 32,
154
+ text: `V:[${node.vector[0]}, ${node.vector[1]}...]`,
155
+ fontSize: 10,
156
+ fontFamily: 'JetBrains Mono',
157
+ fill: '#636e72'
158
+ });
159
+
160
+ group.add(rect);
161
+ group.add(text);
162
+ group.add(vecText);
163
 
164
+ // Interaction: Hover to see Source
165
+ group.on('mouseover', () => {
166
+ document.body.style.cursor = 'pointer';
167
+ rect.fill('#353b48');
168
+ layer.draw();
169
+ });
170
+ group.on('mouseout', () => {
171
+ document.body.style.cursor = 'default';
172
+ rect.fill('#2d3436');
173
+ layer.draw();
174
+ });
175
+
176
+ // Click to log source code
177
+ group.on('click', () => {
178
+ log(`Node Source:\n${node.source}`);
179
+ });
180
+
181
+ layer.add(group);
182
+ nodeMap[node.id] = { group, x, y };
183
  });
184
 
185
+ // Draw Connections (Parent -> Child)
186
  data.connections.forEach(conn => {
187
+ const fromNode = nodeMap[conn.from];
188
+ const toNode = nodeMap[conn.to];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
+ if (fromNode && toNode) {
191
+ // Bezier Connector
192
+ const startX = fromNode.x + 20; // Start from left side for tree-like feel
193
+ const startY = fromNode.y + 50; // Bottom of parent
194
+ const endX = toNode.x + 20; // Top of child
195
+ const endY = toNode.y;
196
 
197
+ // Draw clean elbow lines for code structure
198
+ const points = [
199
+ startX, startY,
200
+ startX, endY - 10,
201
+ endX, endY - 10,
202
+ endX, endY
203
+ ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
 
205
+ const line = new Konva.Line({
206
+ points: points,
207
+ stroke: '#636e72',
208
+ strokeWidth: 2,
209
+ tension: 0.2,
210
+ opacity: 0.6
211
+ });
 
 
 
 
 
 
 
 
 
 
 
212
 
213
+ // Move lines to bottom so nodes are on top
214
+ layer.add(line);
215
+ line.moveToBottom();
216
+ }
 
 
 
 
 
 
 
 
 
 
 
217
  });
218
 
219
+ layer.batchDraw();
220
+
221
+ // Auto-center camera if nodes exist
222
+ if (data.nodes.length > 0) {
223
+ const firstNode = nodeMap[data.nodes[0].id];
224
+ stage.x(50);
225
+ stage.y(50);
226
+ }
227
  }
228
 
229
+ // Initial Call
230
+ setTimeout(() => document.getElementById('btnVisualize').click(), 500);