Spaces:
Running
Running
Add 3 files
Browse files- README.md +7 -5
- index.html +1221 -19
- prompts.txt +1 -0
README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: dataviz-v2
|
| 3 |
+
emoji: 🐳
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: red
|
| 6 |
sdk: static
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite
|
| 10 |
---
|
| 11 |
|
| 12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
index.html
CHANGED
|
@@ -1,19 +1,1221 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>DataViz Dashboard</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
| 9 |
+
<style>
|
| 10 |
+
.dropzone {
|
| 11 |
+
border: 2px dashed #3b82f6;
|
| 12 |
+
border-radius: 0.5rem;
|
| 13 |
+
transition: all 0.3s ease;
|
| 14 |
+
}
|
| 15 |
+
.dropzone.active {
|
| 16 |
+
border-color: #10b981;
|
| 17 |
+
background-color: #f0fdf4;
|
| 18 |
+
}
|
| 19 |
+
.chart-preview {
|
| 20 |
+
transition: all 0.3s ease;
|
| 21 |
+
}
|
| 22 |
+
.chart-preview:hover {
|
| 23 |
+
transform: scale(1.02);
|
| 24 |
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
| 25 |
+
}
|
| 26 |
+
.sidebar {
|
| 27 |
+
transition: all 0.3s ease;
|
| 28 |
+
}
|
| 29 |
+
@media (max-width: 768px) {
|
| 30 |
+
.sidebar {
|
| 31 |
+
transform: translateX(-100%);
|
| 32 |
+
position: absolute;
|
| 33 |
+
z-index: 50;
|
| 34 |
+
height: 100vh;
|
| 35 |
+
}
|
| 36 |
+
.sidebar.open {
|
| 37 |
+
transform: translateX(0);
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
.chart-container {
|
| 41 |
+
min-height: 400px;
|
| 42 |
+
background-color: #f8fafc;
|
| 43 |
+
}
|
| 44 |
+
.data-table {
|
| 45 |
+
max-height: 300px;
|
| 46 |
+
overflow-y: auto;
|
| 47 |
+
}
|
| 48 |
+
/* Custom scrollbar */
|
| 49 |
+
::-webkit-scrollbar {
|
| 50 |
+
width: 8px;
|
| 51 |
+
height: 8px;
|
| 52 |
+
}
|
| 53 |
+
::-webkit-scrollbar-track {
|
| 54 |
+
background: #f1f1f1;
|
| 55 |
+
}
|
| 56 |
+
::-webkit-scrollbar-thumb {
|
| 57 |
+
background: #cbd5e1;
|
| 58 |
+
border-radius: 4px;
|
| 59 |
+
}
|
| 60 |
+
::-webkit-scrollbar-thumb:hover {
|
| 61 |
+
background: #94a3b8;
|
| 62 |
+
}
|
| 63 |
+
</style>
|
| 64 |
+
</head>
|
| 65 |
+
<body class="bg-gray-50 font-sans">
|
| 66 |
+
<div class="flex h-screen overflow-hidden">
|
| 67 |
+
<!-- Mobile menu button -->
|
| 68 |
+
<button id="sidebarToggle" class="md:hidden fixed top-4 left-4 z-50 p-2 rounded-md bg-white shadow-md">
|
| 69 |
+
<i class="fas fa-bars text-blue-500"></i>
|
| 70 |
+
</button>
|
| 71 |
+
|
| 72 |
+
<!-- Sidebar -->
|
| 73 |
+
<div id="sidebar" class="sidebar w-64 bg-white shadow-md flex flex-col">
|
| 74 |
+
<div class="p-4 border-b border-gray-200">
|
| 75 |
+
<h1 class="text-2xl font-bold text-blue-600 flex items-center">
|
| 76 |
+
<i class="fas fa-chart-line mr-2"></i> DataViz
|
| 77 |
+
</h1>
|
| 78 |
+
<p class="text-sm text-gray-500">Interactive Dashboard</p>
|
| 79 |
+
</div>
|
| 80 |
+
|
| 81 |
+
<div class="p-4 space-y-4">
|
| 82 |
+
<div>
|
| 83 |
+
<h3 class="font-medium text-gray-700 mb-2 flex items-center">
|
| 84 |
+
<i class="fas fa-database mr-2 text-blue-500"></i> Data Sources
|
| 85 |
+
</h3>
|
| 86 |
+
<button id="importBtn" class="w-full bg-blue-50 hover:bg-blue-100 text-blue-600 py-2 px-4 rounded-md flex items-center justify-center">
|
| 87 |
+
<i class="fas fa-file-import mr-2"></i> Import Data
|
| 88 |
+
</button>
|
| 89 |
+
<input type="file" id="fileInput" accept=".csv,.xlsx,.xls" class="hidden">
|
| 90 |
+
</div>
|
| 91 |
+
|
| 92 |
+
<div>
|
| 93 |
+
<h3 class="font-medium text-gray-700 mb-2 flex items-center">
|
| 94 |
+
<i class="fas fa-chart-pie mr-2 text-purple-500"></i> Visualization Types
|
| 95 |
+
</h3>
|
| 96 |
+
<div class="space-y-2">
|
| 97 |
+
<button class="viz-type-btn w-full text-left py-2 px-3 rounded-md hover:bg-purple-50 flex items-center" data-type="bar">
|
| 98 |
+
<i class="fas fa-chart-bar mr-2 text-purple-500"></i> Bar Chart
|
| 99 |
+
</button>
|
| 100 |
+
<button class="viz-type-btn w-full text-left py-2 px-3 rounded-md hover:bg-purple-50 flex items-center" data-type="line">
|
| 101 |
+
<i class="fas fa-chart-line mr-2 text-purple-500"></i> Line Chart
|
| 102 |
+
</button>
|
| 103 |
+
<button class="viz-type-btn w-full text-left py-2 px-3 rounded-md hover:bg-purple-50 flex items-center" data-type="pie">
|
| 104 |
+
<i class="fas fa-chart-pie mr-2 text-purple-500"></i> Pie Chart
|
| 105 |
+
</button>
|
| 106 |
+
<button class="viz-type-btn w-full text-left py-2 px-3 rounded-md hover:bg-purple-50 flex items-center" data-type="scatter">
|
| 107 |
+
<i class="fas fa-braille mr-2 text-purple-500"></i> Scatter Plot
|
| 108 |
+
</button>
|
| 109 |
+
<button class="viz-type-btn w-full text-left py-2 px-3 rounded-md hover:bg-purple-50 flex items-center" data-type="flowchart">
|
| 110 |
+
<i class="fas fa-project-diagram mr-2 text-purple-500"></i> Flowchart
|
| 111 |
+
</button>
|
| 112 |
+
<button class="viz-type-btn w-full text-left py-2 px-3 rounded-md hover:bg-purple-50 flex items-center" data-type="mindmap">
|
| 113 |
+
<i class="fas fa-sitemap mr-2 text-purple-500"></i> Mind Map
|
| 114 |
+
</button>
|
| 115 |
+
</div>
|
| 116 |
+
</div>
|
| 117 |
+
|
| 118 |
+
<div>
|
| 119 |
+
<h3 class="font-medium text-gray-700 mb-2 flex items-center">
|
| 120 |
+
<i class="fas fa-magic mr-2 text-green-500"></i> AI Suggestions
|
| 121 |
+
</h3>
|
| 122 |
+
<button id="aiSuggestBtn" class="w-full bg-green-50 hover:bg-green-100 text-green-600 py-2 px-4 rounded-md flex items-center justify-center">
|
| 123 |
+
<i class="fas fa-robot mr-2"></i> Get AI Recommendation
|
| 124 |
+
</button>
|
| 125 |
+
</div>
|
| 126 |
+
|
| 127 |
+
<div>
|
| 128 |
+
<h3 class="font-medium text-gray-700 mb-2 flex items-center">
|
| 129 |
+
<i class="fas fa-tasks mr-2 text-yellow-500"></i> Data Cleaning
|
| 130 |
+
</h3>
|
| 131 |
+
<div class="space-y-2">
|
| 132 |
+
<button class="data-clean-btn w-full text-left py-2 px-3 rounded-md hover:bg-yellow-50 flex items-center" data-action="remove-duplicates">
|
| 133 |
+
<i class="fas fa-backspace mr-2 text-yellow-500"></i> Remove Duplicates
|
| 134 |
+
</button>
|
| 135 |
+
<button class="data-clean-btn w-full text-left py-2 px-3 rounded-md hover:bg-yellow-50 flex items-center" data-action="fill-missing">
|
| 136 |
+
<i class="fas fa-fill-drip mr-2 text-yellow-500"></i> Fill Missing Values
|
| 137 |
+
</button>
|
| 138 |
+
<button class="data-clean-btn w-full text-left py-2 px-3 rounded-md hover:bg-yellow-50 flex items-center" data-action="filter-data">
|
| 139 |
+
<i class="fas fa-filter mr-2 text-yellow-500"></i> Filter Data
|
| 140 |
+
</button>
|
| 141 |
+
</div>
|
| 142 |
+
</div>
|
| 143 |
+
|
| 144 |
+
<div class="pt-4 border-t border-gray-200">
|
| 145 |
+
<h3 class="font-medium text-gray-700 mb-2 flex items-center">
|
| 146 |
+
<i class="fas fa-language mr-2 text-indigo-500"></i> Language
|
| 147 |
+
</h3>
|
| 148 |
+
<select class="w-full p-2 border border-gray-300 rounded-md">
|
| 149 |
+
<option>English</option>
|
| 150 |
+
<option>Spanish</option>
|
| 151 |
+
<option>French</option>
|
| 152 |
+
<option>German</option>
|
| 153 |
+
<option>Chinese</option>
|
| 154 |
+
</select>
|
| 155 |
+
</div>
|
| 156 |
+
</div>
|
| 157 |
+
|
| 158 |
+
<div class="mt-auto p-4 border-t border-gray-200">
|
| 159 |
+
<button id="exportBtn" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-md flex items-center justify-center">
|
| 160 |
+
<i class="fas fa-file-export mr-2"></i> Export Dashboard
|
| 161 |
+
</button>
|
| 162 |
+
</div>
|
| 163 |
+
</div>
|
| 164 |
+
|
| 165 |
+
<!-- Main content -->
|
| 166 |
+
<div class="flex-1 flex flex-col overflow-hidden">
|
| 167 |
+
<!-- Top navigation -->
|
| 168 |
+
<header class="bg-white shadow-sm">
|
| 169 |
+
<div class="px-4 py-3 flex justify-between items-center">
|
| 170 |
+
<div class="flex items-center space-x-4">
|
| 171 |
+
<h2 class="text-xl font-semibold text-gray-800">Dashboard</h2>
|
| 172 |
+
<div class="relative">
|
| 173 |
+
<input type="text" placeholder="Search..." class="pl-8 pr-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
|
| 174 |
+
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
|
| 175 |
+
</div>
|
| 176 |
+
</div>
|
| 177 |
+
<div class="flex items-center space-x-4">
|
| 178 |
+
<button class="p-2 rounded-full hover:bg-gray-100">
|
| 179 |
+
<i class="fas fa-bell text-gray-600"></i>
|
| 180 |
+
</button>
|
| 181 |
+
<div class="flex items-center space-x-2">
|
| 182 |
+
<div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center text-white font-medium">JD</div>
|
| 183 |
+
<span class="text-sm font-medium">John Doe</span>
|
| 184 |
+
</div>
|
| 185 |
+
</div>
|
| 186 |
+
</div>
|
| 187 |
+
</header>
|
| 188 |
+
|
| 189 |
+
<!-- Dashboard content -->
|
| 190 |
+
<main class="flex-1 overflow-y-auto p-4 bg-gray-50">
|
| 191 |
+
<!-- Data import section -->
|
| 192 |
+
<div id="importSection" class="mb-6 bg-white rounded-lg shadow-md p-6">
|
| 193 |
+
<div class="flex justify-between items-center mb-4">
|
| 194 |
+
<h3 class="text-lg font-medium text-gray-800 flex items-center">
|
| 195 |
+
<i class="fas fa-file-import mr-2 text-blue-500"></i> Import Your Data
|
| 196 |
+
</h3>
|
| 197 |
+
<div class="flex space-x-2">
|
| 198 |
+
<button class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-sm">
|
| 199 |
+
<i class="fas fa-question-circle mr-1"></i> Help
|
| 200 |
+
</button>
|
| 201 |
+
<button class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-md text-sm">
|
| 202 |
+
<i class="fas fa-history mr-1"></i> Recent Files
|
| 203 |
+
</button>
|
| 204 |
+
</div>
|
| 205 |
+
</div>
|
| 206 |
+
|
| 207 |
+
<div id="dropzone" class="dropzone p-8 text-center cursor-pointer">
|
| 208 |
+
<div class="flex flex-col items-center justify-center">
|
| 209 |
+
<i class="fas fa-cloud-upload-alt text-4xl text-blue-500 mb-3"></i>
|
| 210 |
+
<h4 class="text-lg font-medium text-gray-700">Drag & drop your file here</h4>
|
| 211 |
+
<p class="text-sm text-gray-500 mb-4">or</p>
|
| 212 |
+
<button id="browseFilesBtn" class="bg-blue-600 hover:bg-blue-700 text-white py-2 px-6 rounded-md">
|
| 213 |
+
Browse Files
|
| 214 |
+
</button>
|
| 215 |
+
<p class="text-xs text-gray-500 mt-3">Supported formats: CSV, XLS, XLSX</p>
|
| 216 |
+
</div>
|
| 217 |
+
</div>
|
| 218 |
+
</div>
|
| 219 |
+
|
| 220 |
+
<!-- Data preview section -->
|
| 221 |
+
<div id="dataPreviewSection" class="mb-6 bg-white rounded-lg shadow-md p-6 hidden">
|
| 222 |
+
<div class="flex justify-between items-center mb-4">
|
| 223 |
+
<h3 class="text-lg font-medium text-gray-800 flex items-center">
|
| 224 |
+
<i class="fas fa-table mr-2 text-green-500"></i> Data Preview
|
| 225 |
+
</h3>
|
| 226 |
+
<div class="flex space-x-2">
|
| 227 |
+
<button id="editDataBtn" class="px-3 py-1 bg-blue-50 hover:bg-blue-100 text-blue-600 rounded-md text-sm flex items-center">
|
| 228 |
+
<i class="fas fa-edit mr-1"></i> Edit
|
| 229 |
+
</button>
|
| 230 |
+
<button id="transformDataBtn" class="px-3 py-1 bg-purple-50 hover:bg-purple-100 text-purple-600 rounded-md text-sm flex items-center">
|
| 231 |
+
<i class="fas fa-exchange-alt mr-1"></i> Transform
|
| 232 |
+
</button>
|
| 233 |
+
</div>
|
| 234 |
+
</div>
|
| 235 |
+
|
| 236 |
+
<div class="data-table border border-gray-200 rounded-md overflow-hidden">
|
| 237 |
+
<table class="min-w-full divide-y divide-gray-200">
|
| 238 |
+
<thead class="bg-gray-50">
|
| 239 |
+
<tr id="tableHeaders">
|
| 240 |
+
<!-- Headers will be populated by JavaScript -->
|
| 241 |
+
</tr>
|
| 242 |
+
</thead>
|
| 243 |
+
<tbody class="bg-white divide-y divide-gray-200" id="tableBody">
|
| 244 |
+
<!-- Data will be populated by JavaScript -->
|
| 245 |
+
</tbody>
|
| 246 |
+
</table>
|
| 247 |
+
</div>
|
| 248 |
+
</div>
|
| 249 |
+
|
| 250 |
+
<!-- Visualization workspace -->
|
| 251 |
+
<div id="vizWorkspace" class="bg-white rounded-lg shadow-md p-6 hidden">
|
| 252 |
+
<div class="flex justify-between items-center mb-4">
|
| 253 |
+
<h3 class="text-lg font-medium text-gray-800 flex items-center">
|
| 254 |
+
<i class="fas fa-chart-area mr-2 text-purple-500"></i> Visualization Workspace
|
| 255 |
+
</h3>
|
| 256 |
+
<div class="flex space-x-2">
|
| 257 |
+
<button id="saveVizBtn" class="px-3 py-1 bg-green-50 hover:bg-green-100 text-green-600 rounded-md text-sm flex items-center">
|
| 258 |
+
<i class="fas fa-save mr-1"></i> Save
|
| 259 |
+
</button>
|
| 260 |
+
<button id="resetVizBtn" class="px-3 py-1 bg-red-50 hover:bg-red-100 text-red-600 rounded-md text-sm flex items-center">
|
| 261 |
+
<i class="fas fa-redo mr-1"></i> Reset
|
| 262 |
+
</button>
|
| 263 |
+
</div>
|
| 264 |
+
</div>
|
| 265 |
+
|
| 266 |
+
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
| 267 |
+
<!-- Visualization controls -->
|
| 268 |
+
<div class="lg:col-span-1 bg-gray-50 p-4 rounded-lg">
|
| 269 |
+
<div class="space-y-4">
|
| 270 |
+
<div>
|
| 271 |
+
<label class="block text-sm font-medium text-gray-700 mb-1">Chart Type</label>
|
| 272 |
+
<select id="chartTypeSelect" class="w-full p-2 border border-gray-300 rounded-md">
|
| 273 |
+
<option value="bar">Bar Chart</option>
|
| 274 |
+
<option value="line">Line Chart</option>
|
| 275 |
+
<option value="pie">Pie Chart</option>
|
| 276 |
+
<option value="scatter">Scatter Plot</option>
|
| 277 |
+
<option value="flowchart">Flowchart</option>
|
| 278 |
+
<option value="mindmap">Mind Map</option>
|
| 279 |
+
</select>
|
| 280 |
+
</div>
|
| 281 |
+
|
| 282 |
+
<div>
|
| 283 |
+
<label class="block text-sm font-medium text-gray-700 mb-1">X-Axis</label>
|
| 284 |
+
<select id="xAxisSelect" class="w-full p-2 border border-gray-300 rounded-md">
|
| 285 |
+
<!-- Options will be populated by JavaScript -->
|
| 286 |
+
</select>
|
| 287 |
+
</div>
|
| 288 |
+
|
| 289 |
+
<div>
|
| 290 |
+
<label class="block text-sm font-medium text-gray-700 mb-1">Y-Axis</label>
|
| 291 |
+
<select id="yAxisSelect" class="w-full p-2 border border-gray-300 rounded-md">
|
| 292 |
+
<!-- Options will be populated by JavaScript -->
|
| 293 |
+
</select>
|
| 294 |
+
</div>
|
| 295 |
+
|
| 296 |
+
<div>
|
| 297 |
+
<label class="block text-sm font-medium text-gray-700 mb-1">Color Scheme</label>
|
| 298 |
+
<select id="colorSchemeSelect" class="w-full p-2 border border-gray-300 rounded-md">
|
| 299 |
+
<option value="default">Default</option>
|
| 300 |
+
<option value="rainbow">Rainbow</option>
|
| 301 |
+
<option value="pastel">Pastel</option>
|
| 302 |
+
<option value="warm">Warm</option>
|
| 303 |
+
<option value="cool">Cool</option>
|
| 304 |
+
<option value="monochrome">Monochrome</option>
|
| 305 |
+
</select>
|
| 306 |
+
</div>
|
| 307 |
+
|
| 308 |
+
<div>
|
| 309 |
+
<label class="block text-sm font-medium text-gray-700 mb-1">Chart Title</label>
|
| 310 |
+
<input type="text" id="chartTitleInput" class="w-full p-2 border border-gray-300 rounded-md" placeholder="Enter chart title">
|
| 311 |
+
</div>
|
| 312 |
+
|
| 313 |
+
<div class="pt-2">
|
| 314 |
+
<button id="updateChartBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-md">
|
| 315 |
+
Update Visualization
|
| 316 |
+
</button>
|
| 317 |
+
</div>
|
| 318 |
+
</div>
|
| 319 |
+
</div>
|
| 320 |
+
|
| 321 |
+
<!-- Visualization preview -->
|
| 322 |
+
<div class="lg:col-span-2">
|
| 323 |
+
<div class="chart-container border border-gray-200 rounded-md p-4 flex items-center justify-center">
|
| 324 |
+
<div id="chartPlaceholder" class="text-center text-gray-500">
|
| 325 |
+
<i class="fas fa-chart-bar text-5xl mb-3"></i>
|
| 326 |
+
<p>Select data and chart type to generate visualization</p>
|
| 327 |
+
</div>
|
| 328 |
+
<canvas id="chartCanvas" class="hidden"></canvas>
|
| 329 |
+
<div id="flowchartContainer" class="hidden w-full h-full"></div>
|
| 330 |
+
<div id="mindmapContainer" class="hidden w-full h-full"></div>
|
| 331 |
+
</div>
|
| 332 |
+
</div>
|
| 333 |
+
</div>
|
| 334 |
+
</div>
|
| 335 |
+
|
| 336 |
+
<!-- AI recommendation section -->
|
| 337 |
+
<div id="aiRecommendationSection" class="bg-white rounded-lg shadow-md p-6 hidden">
|
| 338 |
+
<div class="flex justify-between items-center mb-4">
|
| 339 |
+
<h3 class="text-lg font-medium text-gray-800 flex items-center">
|
| 340 |
+
<i class="fas fa-robot mr-2 text-green-500"></i> AI Recommendation
|
| 341 |
+
</h3>
|
| 342 |
+
<button id="applyAiRecommendationBtn" class="px-3 py-1 bg-green-50 hover:bg-green-100 text-green-600 rounded-md text-sm flex items-center">
|
| 343 |
+
<i class="fas fa-check-circle mr-1"></i> Apply Recommendation
|
| 344 |
+
</button>
|
| 345 |
+
</div>
|
| 346 |
+
|
| 347 |
+
<div class="bg-blue-50 p-4 rounded-md">
|
| 348 |
+
<div class="flex items-start">
|
| 349 |
+
<div class="flex-shrink-0 bg-blue-100 p-2 rounded-full">
|
| 350 |
+
<i class="fas fa-lightbulb text-blue-500"></i>
|
| 351 |
+
</div>
|
| 352 |
+
<div class="ml-3">
|
| 353 |
+
<h4 class="text-sm font-medium text-blue-800">Based on your data, we recommend:</h4>
|
| 354 |
+
<p id="aiRecommendationText" class="text-sm text-blue-700 mt-1">
|
| 355 |
+
<!-- AI recommendation will be inserted here -->
|
| 356 |
+
</p>
|
| 357 |
+
</div>
|
| 358 |
+
</div>
|
| 359 |
+
</div>
|
| 360 |
+
</div>
|
| 361 |
+
|
| 362 |
+
<!-- Dashboard templates -->
|
| 363 |
+
<div id="templatesSection" class="mt-6 hidden">
|
| 364 |
+
<div class="flex justify-between items-center mb-4">
|
| 365 |
+
<h3 class="text-lg font-medium text-gray-800 flex items-center">
|
| 366 |
+
<i class="fas fa-clone mr-2 text-indigo-500"></i> Dashboard Templates
|
| 367 |
+
</h3>
|
| 368 |
+
<button class="px-3 py-1 bg-indigo-50 hover:bg-indigo-100 text-indigo-600 rounded-md text-sm flex items-center">
|
| 369 |
+
<i class="fas fa-plus mr-1"></i> New Template
|
| 370 |
+
</button>
|
| 371 |
+
</div>
|
| 372 |
+
|
| 373 |
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
| 374 |
+
<div class="template-card bg-white rounded-lg shadow-md overflow-hidden border border-gray-200 hover:border-blue-300 cursor-pointer">
|
| 375 |
+
<div class="h-32 bg-gradient-to-r from-blue-400 to-blue-600 flex items-center justify-center">
|
| 376 |
+
<i class="fas fa-chart-bar text-white text-4xl"></i>
|
| 377 |
+
</div>
|
| 378 |
+
<div class="p-4">
|
| 379 |
+
<h4 class="font-medium text-gray-800">Sales Dashboard</h4>
|
| 380 |
+
<p class="text-sm text-gray-500 mt-1">Track sales performance and trends</p>
|
| 381 |
+
</div>
|
| 382 |
+
</div>
|
| 383 |
+
|
| 384 |
+
<div class="template-card bg-white rounded-lg shadow-md overflow-hidden border border-gray-200 hover:border-blue-300 cursor-pointer">
|
| 385 |
+
<div class="h-32 bg-gradient-to-r from-purple-400 to-purple-600 flex items-center justify-center">
|
| 386 |
+
<i class="fas fa-users text-white text-4xl"></i>
|
| 387 |
+
</div>
|
| 388 |
+
<div class="p-4">
|
| 389 |
+
<h4 class="font-medium text-gray-800">Customer Analytics</h4>
|
| 390 |
+
<p class="text-sm text-gray-500 mt-1">Analyze customer behavior and demographics</p>
|
| 391 |
+
</div>
|
| 392 |
+
</div>
|
| 393 |
+
|
| 394 |
+
<div class="template-card bg-white rounded-lg shadow-md overflow-hidden border border-gray-200 hover:border-blue-300 cursor-pointer">
|
| 395 |
+
<div class="h-32 bg-gradient-to-r from-green-400 to-green-600 flex items-center justify-center">
|
| 396 |
+
<i class="fas fa-project-diagram text-white text-4xl"></i>
|
| 397 |
+
</div>
|
| 398 |
+
<div class="p-4">
|
| 399 |
+
<h4 class="font-medium text-gray-800">Process Flow</h4>
|
| 400 |
+
<p class="text-sm text-gray-500 mt-1">Visualize workflows and processes</p>
|
| 401 |
+
</div>
|
| 402 |
+
</div>
|
| 403 |
+
</div>
|
| 404 |
+
</div>
|
| 405 |
+
</main>
|
| 406 |
+
</div>
|
| 407 |
+
</div>
|
| 408 |
+
|
| 409 |
+
<!-- Modal for data editing -->
|
| 410 |
+
<div id="editDataModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
|
| 411 |
+
<div class="bg-white rounded-lg shadow-xl w-full max-w-4xl max-h-screen overflow-auto">
|
| 412 |
+
<div class="p-4 border-b border-gray-200 flex justify-between items-center">
|
| 413 |
+
<h3 class="text-lg font-medium text-gray-800">Edit Data</h3>
|
| 414 |
+
<button id="closeEditModalBtn" class="text-gray-500 hover:text-gray-700">
|
| 415 |
+
<i class="fas fa-times"></i>
|
| 416 |
+
</button>
|
| 417 |
+
</div>
|
| 418 |
+
<div class="p-4">
|
| 419 |
+
<div class="overflow-x-auto">
|
| 420 |
+
<table class="min-w-full divide-y divide-gray-200">
|
| 421 |
+
<thead class="bg-gray-50">
|
| 422 |
+
<tr id="editTableHeaders">
|
| 423 |
+
<!-- Headers will be populated by JavaScript -->
|
| 424 |
+
</tr>
|
| 425 |
+
</thead>
|
| 426 |
+
<tbody class="bg-white divide-y divide-gray-200" id="editTableBody">
|
| 427 |
+
<!-- Data will be populated by JavaScript -->
|
| 428 |
+
</tbody>
|
| 429 |
+
</table>
|
| 430 |
+
</div>
|
| 431 |
+
</div>
|
| 432 |
+
<div class="p-4 border-t border-gray-200 flex justify-end space-x-3">
|
| 433 |
+
<button id="cancelEditBtn" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">
|
| 434 |
+
Cancel
|
| 435 |
+
</button>
|
| 436 |
+
<button id="saveEditBtn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
|
| 437 |
+
Save Changes
|
| 438 |
+
</button>
|
| 439 |
+
</div>
|
| 440 |
+
</div>
|
| 441 |
+
</div>
|
| 442 |
+
|
| 443 |
+
<!-- Modal for export options -->
|
| 444 |
+
<div id="exportModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
|
| 445 |
+
<div class="bg-white rounded-lg shadow-xl w-full max-w-md">
|
| 446 |
+
<div class="p-4 border-b border-gray-200 flex justify-between items-center">
|
| 447 |
+
<h3 class="text-lg font-medium text-gray-800">Export Options</h3>
|
| 448 |
+
<button id="closeExportModalBtn" class="text-gray-500 hover:text-gray-700">
|
| 449 |
+
<i class="fas fa-times"></i>
|
| 450 |
+
</button>
|
| 451 |
+
</div>
|
| 452 |
+
<div class="p-4">
|
| 453 |
+
<div class="space-y-4">
|
| 454 |
+
<div>
|
| 455 |
+
<label class="block text-sm font-medium text-gray-700 mb-2">Export Format</label>
|
| 456 |
+
<div class="grid grid-cols-3 gap-2">
|
| 457 |
+
<button class="export-format-btn p-3 border border-gray-300 rounded-md hover:bg-gray-50 flex flex-col items-center" data-format="png">
|
| 458 |
+
<i class="fas fa-image text-2xl text-blue-500 mb-1"></i>
|
| 459 |
+
<span class="text-xs">PNG</span>
|
| 460 |
+
</button>
|
| 461 |
+
<button class="export-format-btn p-3 border border-gray-300 rounded-md hover:bg-gray-50 flex flex-col items-center" data-format="jpg">
|
| 462 |
+
<i class="fas fa-image text-2xl text-green-500 mb-1"></i>
|
| 463 |
+
<span class="text-xs">JPG</span>
|
| 464 |
+
</button>
|
| 465 |
+
<button class="export-format-btn p-3 border border-gray-300 rounded-md hover:bg-gray-50 flex flex-col items-center" data-format="pdf">
|
| 466 |
+
<i class="fas fa-file-pdf text-2xl text-red-500 mb-1"></i>
|
| 467 |
+
<span class="text-xs">PDF</span>
|
| 468 |
+
</button>
|
| 469 |
+
<button class="export-format-btn p-3 border border-gray-300 rounded-md hover:bg-gray-50 flex flex-col items-center" data-format="svg">
|
| 470 |
+
<i class="fas fa-file-code text-2xl text-purple-500 mb-1"></i>
|
| 471 |
+
<span class="text-xs">SVG</span>
|
| 472 |
+
</button>
|
| 473 |
+
<button class="export-format-btn p-3 border border-gray-300 rounded-md hover:bg-gray-50 flex flex-col items-center" data-format="csv">
|
| 474 |
+
<i class="fas fa-file-csv text-2xl text-yellow-500 mb-1"></i>
|
| 475 |
+
<span class="text-xs">CSV</span>
|
| 476 |
+
</button>
|
| 477 |
+
<button class="export-format-btn p-3 border border-gray-300 rounded-md hover:bg-gray-50 flex flex-col items-center" data-format="json">
|
| 478 |
+
<i class="fas fa-file-code text-2xl text-indigo-500 mb-1"></i>
|
| 479 |
+
<span class="text-xs">JSON</span>
|
| 480 |
+
</button>
|
| 481 |
+
</div>
|
| 482 |
+
</div>
|
| 483 |
+
<div>
|
| 484 |
+
<label class="block text-sm font-medium text-gray-700 mb-1">Quality</label>
|
| 485 |
+
<select class="w-full p-2 border border-gray-300 rounded-md">
|
| 486 |
+
<option>High (300dpi)</option>
|
| 487 |
+
<option>Medium (150dpi)</option>
|
| 488 |
+
<option>Low (72dpi)</option>
|
| 489 |
+
</select>
|
| 490 |
+
</div>
|
| 491 |
+
<div>
|
| 492 |
+
<label class="block text-sm font-medium text-gray-700 mb-1">Size</label>
|
| 493 |
+
<select class="w-full p-2 border border-gray-300 rounded-md">
|
| 494 |
+
<option>Original Size</option>
|
| 495 |
+
<option>A4 (210 × 297mm)</option>
|
| 496 |
+
<option>Letter (216 × 279mm)</option>
|
| 497 |
+
<option>Custom...</option>
|
| 498 |
+
</select>
|
| 499 |
+
</div>
|
| 500 |
+
</div>
|
| 501 |
+
</div>
|
| 502 |
+
<div class="p-4 border-t border-gray-200 flex justify-end space-x-3">
|
| 503 |
+
<button id="cancelExportBtn" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">
|
| 504 |
+
Cancel
|
| 505 |
+
</button>
|
| 506 |
+
<button id="confirmExportBtn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
|
| 507 |
+
Export
|
| 508 |
+
</button>
|
| 509 |
+
</div>
|
| 510 |
+
</div>
|
| 511 |
+
</div>
|
| 512 |
+
|
| 513 |
+
<script>
|
| 514 |
+
// Sample data for demonstration
|
| 515 |
+
let sampleData = [
|
| 516 |
+
{ id: 1, product: 'Laptop', category: 'Electronics', sales: 1200, profit: 300, region: 'North' },
|
| 517 |
+
{ id: 2, product: 'Smartphone', category: 'Electronics', sales: 800, profit: 200, region: 'South' },
|
| 518 |
+
{ id: 3, product: 'Desk', category: 'Furniture', sales: 450, profit: 150, region: 'East' },
|
| 519 |
+
{ id: 4, product: 'Chair', category: 'Furniture', sales: 250, profit: 75, region: 'West' },
|
| 520 |
+
{ id: 5, product: 'Monitor', category: 'Electronics', sales: 350, profit: 100, region: 'North' },
|
| 521 |
+
{ id: 6, product: 'Keyboard', category: 'Electronics', sales: 100, profit: 25, region: 'South' },
|
| 522 |
+
{ id: 7, product: 'Mouse', category: 'Electronics', sales: 50, profit: 15, region: 'East' },
|
| 523 |
+
{ id: 8, product: 'Table', category: 'Furniture', sales: 600, profit: 180, region: 'West' }
|
| 524 |
+
];
|
| 525 |
+
|
| 526 |
+
// DOM elements
|
| 527 |
+
const sidebar = document.getElementById('sidebar');
|
| 528 |
+
const sidebarToggle = document.getElementById('sidebarToggle');
|
| 529 |
+
const importBtn = document.getElementById('importBtn');
|
| 530 |
+
const browseFilesBtn = document.getElementById('browseFilesBtn');
|
| 531 |
+
const fileInput = document.getElementById('fileInput');
|
| 532 |
+
const dropzone = document.getElementById('dropzone');
|
| 533 |
+
const dataPreviewSection = document.getElementById('dataPreviewSection');
|
| 534 |
+
const vizWorkspace = document.getElementById('vizWorkspace');
|
| 535 |
+
const aiRecommendationSection = document.getElementById('aiRecommendationSection');
|
| 536 |
+
const templatesSection = document.getElementById('templatesSection');
|
| 537 |
+
const tableHeaders = document.getElementById('tableHeaders');
|
| 538 |
+
const tableBody = document.getElementById('tableBody');
|
| 539 |
+
const editDataModal = document.getElementById('editDataModal');
|
| 540 |
+
const closeEditModalBtn = document.getElementById('closeEditModalBtn');
|
| 541 |
+
const editTableHeaders = document.getElementById('editTableHeaders');
|
| 542 |
+
const editTableBody = document.getElementById('editTableBody');
|
| 543 |
+
const cancelEditBtn = document.getElementById('cancelEditBtn');
|
| 544 |
+
const saveEditBtn = document.getElementById('saveEditBtn');
|
| 545 |
+
const exportBtn = document.getElementById('exportBtn');
|
| 546 |
+
const exportModal = document.getElementById('exportModal');
|
| 547 |
+
const closeExportModalBtn = document.getElementById('closeExportModalBtn');
|
| 548 |
+
const cancelExportBtn = document.getElementById('cancelExportBtn');
|
| 549 |
+
const confirmExportBtn = document.getElementById('confirmExportBtn');
|
| 550 |
+
const exportFormatBtns = document.querySelectorAll('.export-format-btn');
|
| 551 |
+
const chartTypeSelect = document.getElementById('chartTypeSelect');
|
| 552 |
+
const xAxisSelect = document.getElementById('xAxisSelect');
|
| 553 |
+
const yAxisSelect = document.getElementById('yAxisSelect');
|
| 554 |
+
const colorSchemeSelect = document.getElementById('colorSchemeSelect');
|
| 555 |
+
const chartTitleInput = document.getElementById('chartTitleInput');
|
| 556 |
+
const updateChartBtn = document.getElementById('updateChartBtn');
|
| 557 |
+
const chartPlaceholder = document.getElementById('chartPlaceholder');
|
| 558 |
+
const chartCanvas = document.getElementById('chartCanvas');
|
| 559 |
+
const flowchartContainer = document.getElementById('flowchartContainer');
|
| 560 |
+
const mindmapContainer = document.getElementById('mindmapContainer');
|
| 561 |
+
const aiSuggestBtn = document.getElementById('aiSuggestBtn');
|
| 562 |
+
const aiRecommendationText = document.getElementById('aiRecommendationText');
|
| 563 |
+
const applyAiRecommendationBtn = document.getElementById('applyAiRecommendationBtn');
|
| 564 |
+
const vizTypeBtns = document.querySelectorAll('.viz-type-btn');
|
| 565 |
+
const dataCleanBtns = document.querySelectorAll('.data-clean-btn');
|
| 566 |
+
|
| 567 |
+
// Current state
|
| 568 |
+
let currentData = [];
|
| 569 |
+
let currentChart = null;
|
| 570 |
+
let currentVizType = 'bar';
|
| 571 |
+
|
| 572 |
+
// Initialize the app
|
| 573 |
+
function init() {
|
| 574 |
+
// Toggle sidebar on mobile
|
| 575 |
+
sidebarToggle.addEventListener('click', () => {
|
| 576 |
+
sidebar.classList.toggle('open');
|
| 577 |
+
});
|
| 578 |
+
|
| 579 |
+
// Import button click
|
| 580 |
+
importBtn.addEventListener('click', () => {
|
| 581 |
+
fileInput.click();
|
| 582 |
+
});
|
| 583 |
+
|
| 584 |
+
// Browse files button
|
| 585 |
+
browseFilesBtn.addEventListener('click', () => {
|
| 586 |
+
fileInput.click();
|
| 587 |
+
});
|
| 588 |
+
|
| 589 |
+
// File input change
|
| 590 |
+
fileInput.addEventListener('change', handleFileSelect);
|
| 591 |
+
|
| 592 |
+
// Drag and drop events
|
| 593 |
+
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
| 594 |
+
dropzone.addEventListener(eventName, preventDefaults, false);
|
| 595 |
+
});
|
| 596 |
+
|
| 597 |
+
['dragenter', 'dragover'].forEach(eventName => {
|
| 598 |
+
dropzone.addEventListener(eventName, highlight, false);
|
| 599 |
+
});
|
| 600 |
+
|
| 601 |
+
['dragleave', 'drop'].forEach(eventName => {
|
| 602 |
+
dropzone.addEventListener(eventName, unhighlight, false);
|
| 603 |
+
});
|
| 604 |
+
|
| 605 |
+
dropzone.addEventListener('drop', handleDrop, false);
|
| 606 |
+
|
| 607 |
+
// Visualization type buttons
|
| 608 |
+
vizTypeBtns.forEach(btn => {
|
| 609 |
+
btn.addEventListener('click', () => {
|
| 610 |
+
const type = btn.dataset.type;
|
| 611 |
+
currentVizType = type;
|
| 612 |
+
chartTypeSelect.value = type;
|
| 613 |
+
updateVizControls();
|
| 614 |
+
if (currentData.length > 0) {
|
| 615 |
+
renderVisualization();
|
| 616 |
+
} else {
|
| 617 |
+
alert('Please import data first');
|
| 618 |
+
}
|
| 619 |
+
});
|
| 620 |
+
});
|
| 621 |
+
|
| 622 |
+
// Data cleaning buttons
|
| 623 |
+
dataCleanBtns.forEach(btn => {
|
| 624 |
+
btn.addEventListener('click', () => {
|
| 625 |
+
const action = btn.dataset.action;
|
| 626 |
+
performDataCleaning(action);
|
| 627 |
+
});
|
| 628 |
+
});
|
| 629 |
+
|
| 630 |
+
// Edit data modal
|
| 631 |
+
closeEditModalBtn.addEventListener('click', () => {
|
| 632 |
+
editDataModal.classList.add('hidden');
|
| 633 |
+
});
|
| 634 |
+
|
| 635 |
+
cancelEditBtn.addEventListener('click', () => {
|
| 636 |
+
editDataModal.classList.add('hidden');
|
| 637 |
+
});
|
| 638 |
+
|
| 639 |
+
saveEditBtn.addEventListener('click', () => {
|
| 640 |
+
// In a real app, we would save the edited data
|
| 641 |
+
editDataModal.classList.add('hidden');
|
| 642 |
+
alert('Data changes saved successfully!');
|
| 643 |
+
});
|
| 644 |
+
|
| 645 |
+
// Export modal
|
| 646 |
+
exportBtn.addEventListener('click', () => {
|
| 647 |
+
exportModal.classList.remove('hidden');
|
| 648 |
+
});
|
| 649 |
+
|
| 650 |
+
closeExportModalBtn.addEventListener('click', () => {
|
| 651 |
+
exportModal.classList.add('hidden');
|
| 652 |
+
});
|
| 653 |
+
|
| 654 |
+
cancelExportBtn.addEventListener('click', () => {
|
| 655 |
+
exportModal.classList.add('hidden');
|
| 656 |
+
});
|
| 657 |
+
|
| 658 |
+
confirmExportBtn.addEventListener('click', () => {
|
| 659 |
+
exportModal.classList.add('hidden');
|
| 660 |
+
alert('Export initiated! In a real app, this would download the file.');
|
| 661 |
+
});
|
| 662 |
+
|
| 663 |
+
exportFormatBtns.forEach(btn => {
|
| 664 |
+
btn.addEventListener('click', () => {
|
| 665 |
+
const format = btn.dataset.format;
|
| 666 |
+
alert(`Preparing to export as ${format.toUpperCase()}`);
|
| 667 |
+
});
|
| 668 |
+
});
|
| 669 |
+
|
| 670 |
+
// Chart controls
|
| 671 |
+
chartTypeSelect.addEventListener('change', () => {
|
| 672 |
+
currentVizType = chartTypeSelect.value;
|
| 673 |
+
updateVizControls();
|
| 674 |
+
});
|
| 675 |
+
|
| 676 |
+
updateChartBtn.addEventListener('click', renderVisualization);
|
| 677 |
+
|
| 678 |
+
// AI suggestion
|
| 679 |
+
aiSuggestBtn.addEventListener('click', generateAiRecommendation);
|
| 680 |
+
|
| 681 |
+
applyAiRecommendationBtn.addEventListener('click', applyAiRecommendation);
|
| 682 |
+
|
| 683 |
+
// Load sample data for demo
|
| 684 |
+
loadSampleData();
|
| 685 |
+
}
|
| 686 |
+
|
| 687 |
+
// Load sample data for demonstration
|
| 688 |
+
function loadSampleData() {
|
| 689 |
+
currentData = [...sampleData];
|
| 690 |
+
renderDataPreview();
|
| 691 |
+
dataPreviewSection.classList.remove('hidden');
|
| 692 |
+
vizWorkspace.classList.remove('hidden');
|
| 693 |
+
templatesSection.classList.remove('hidden');
|
| 694 |
+
updateVizControls();
|
| 695 |
+
}
|
| 696 |
+
|
| 697 |
+
// Handle file selection
|
| 698 |
+
function handleFileSelect(e) {
|
| 699 |
+
const files = e.target.files;
|
| 700 |
+
if (files.length > 0) {
|
| 701 |
+
processFile(files[0]);
|
| 702 |
+
}
|
| 703 |
+
}
|
| 704 |
+
|
| 705 |
+
// Handle drop event
|
| 706 |
+
function handleDrop(e) {
|
| 707 |
+
const dt = e.dataTransfer;
|
| 708 |
+
const files = dt.files;
|
| 709 |
+
if (files.length > 0) {
|
| 710 |
+
processFile(files[0]);
|
| 711 |
+
}
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
// Process uploaded file
|
| 715 |
+
function processFile(file) {
|
| 716 |
+
const fileType = file.name.split('.').pop().toLowerCase();
|
| 717 |
+
|
| 718 |
+
if (fileType === 'csv') {
|
| 719 |
+
// In a real app, we would parse the CSV file
|
| 720 |
+
alert(`CSV file "${file.name}" selected. In a real app, we would parse this file.`);
|
| 721 |
+
loadSampleData(); // For demo purposes
|
| 722 |
+
} else if (fileType === 'xlsx' || fileType === 'xls') {
|
| 723 |
+
// In a real app, we would parse the Excel file
|
| 724 |
+
alert(`Excel file "${file.name}" selected. In a real app, we would parse this file.`);
|
| 725 |
+
loadSampleData(); // For demo purposes
|
| 726 |
+
} else {
|
| 727 |
+
alert('Unsupported file type. Please upload a CSV or Excel file.');
|
| 728 |
+
}
|
| 729 |
+
}
|
| 730 |
+
|
| 731 |
+
// Prevent default drag and drop behaviors
|
| 732 |
+
function preventDefaults(e) {
|
| 733 |
+
e.preventDefault();
|
| 734 |
+
e.stopPropagation();
|
| 735 |
+
}
|
| 736 |
+
|
| 737 |
+
// Highlight dropzone
|
| 738 |
+
function highlight() {
|
| 739 |
+
dropzone.classList.add('active');
|
| 740 |
+
}
|
| 741 |
+
|
| 742 |
+
// Unhighlight dropzone
|
| 743 |
+
function unhighlight() {
|
| 744 |
+
dropzone.classList.remove('active');
|
| 745 |
+
}
|
| 746 |
+
|
| 747 |
+
// Render data preview
|
| 748 |
+
function renderDataPreview() {
|
| 749 |
+
if (currentData.length === 0) return;
|
| 750 |
+
|
| 751 |
+
// Clear existing content
|
| 752 |
+
tableHeaders.innerHTML = '';
|
| 753 |
+
tableBody.innerHTML = '';
|
| 754 |
+
|
| 755 |
+
// Get headers from first object
|
| 756 |
+
const headers = Object.keys(currentData[0]);
|
| 757 |
+
|
| 758 |
+
// Create header row
|
| 759 |
+
headers.forEach(header => {
|
| 760 |
+
const th = document.createElement('th');
|
| 761 |
+
th.className = 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider';
|
| 762 |
+
th.textContent = header;
|
| 763 |
+
tableHeaders.appendChild(th);
|
| 764 |
+
});
|
| 765 |
+
|
| 766 |
+
// Create data rows (limit to 10 for preview)
|
| 767 |
+
const previewData = currentData.slice(0, 10);
|
| 768 |
+
previewData.forEach(row => {
|
| 769 |
+
const tr = document.createElement('tr');
|
| 770 |
+
headers.forEach(header => {
|
| 771 |
+
const td = document.createElement('td');
|
| 772 |
+
td.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500';
|
| 773 |
+
td.textContent = row[header];
|
| 774 |
+
tr.appendChild(td);
|
| 775 |
+
});
|
| 776 |
+
tableBody.appendChild(tr);
|
| 777 |
+
});
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
// Update visualization controls based on current data and type
|
| 781 |
+
function updateVizControls() {
|
| 782 |
+
if (currentData.length === 0) return;
|
| 783 |
+
|
| 784 |
+
// Get headers from first object
|
| 785 |
+
const headers = Object.keys(currentData[0]);
|
| 786 |
+
|
| 787 |
+
// Clear existing options
|
| 788 |
+
xAxisSelect.innerHTML = '';
|
| 789 |
+
yAxisSelect.innerHTML = '';
|
| 790 |
+
|
| 791 |
+
// Add options based on chart type
|
| 792 |
+
if (currentVizType === 'bar' || currentVizType === 'line') {
|
| 793 |
+
headers.forEach(header => {
|
| 794 |
+
xAxisSelect.add(new Option(header, header));
|
| 795 |
+
});
|
| 796 |
+
|
| 797 |
+
// For Y-axis, only include numeric columns
|
| 798 |
+
headers.forEach(header => {
|
| 799 |
+
if (typeof currentData[0][header] === 'number') {
|
| 800 |
+
yAxisSelect.add(new Option(header, header));
|
| 801 |
+
}
|
| 802 |
+
});
|
| 803 |
+
|
| 804 |
+
// Set default selections
|
| 805 |
+
xAxisSelect.value = headers[0];
|
| 806 |
+
yAxisSelect.value = headers.find(h => typeof currentData[0][h] === 'number');
|
| 807 |
+
}
|
| 808 |
+
else if (currentVizType === 'pie') {
|
| 809 |
+
headers.forEach(header => {
|
| 810 |
+
xAxisSelect.add(new Option(header, header));
|
| 811 |
+
});
|
| 812 |
+
|
| 813 |
+
// For pie charts, only include numeric columns for values
|
| 814 |
+
headers.forEach(header => {
|
| 815 |
+
if (typeof currentData[0][header] === 'number') {
|
| 816 |
+
yAxisSelect.add(new Option(header, header));
|
| 817 |
+
}
|
| 818 |
+
});
|
| 819 |
+
|
| 820 |
+
// Set default selections
|
| 821 |
+
xAxisSelect.value = headers[0];
|
| 822 |
+
yAxisSelect.value = headers.find(h => typeof currentData[0][h] === 'number');
|
| 823 |
+
}
|
| 824 |
+
else if (currentVizType === 'scatter') {
|
| 825 |
+
// For scatter plots, both axes should be numeric
|
| 826 |
+
headers.forEach(header => {
|
| 827 |
+
if (typeof currentData[0][header] === 'number') {
|
| 828 |
+
xAxisSelect.add(new Option(header, header));
|
| 829 |
+
yAxisSelect.add(new Option(header, header));
|
| 830 |
+
}
|
| 831 |
+
});
|
| 832 |
+
|
| 833 |
+
// Set default selections
|
| 834 |
+
const numericHeaders = headers.filter(h => typeof currentData[0][h] === 'number');
|
| 835 |
+
xAxisSelect.value = numericHeaders[0];
|
| 836 |
+
yAxisSelect.value = numericHeaders[1] || numericHeaders[0];
|
| 837 |
+
}
|
| 838 |
+
else if (currentVizType === 'flowchart' || currentVizType === 'mindmap') {
|
| 839 |
+
// For diagrams, we need different controls
|
| 840 |
+
// Simplified for this demo
|
| 841 |
+
xAxisSelect.innerHTML = '<option value="nodes">Nodes</option>';
|
| 842 |
+
yAxisSelect.innerHTML = '<option value="connections">Connections</option>';
|
| 843 |
+
}
|
| 844 |
+
}
|
| 845 |
+
|
| 846 |
+
// Render visualization based on current selections
|
| 847 |
+
function renderVisualization() {
|
| 848 |
+
if (currentData.length === 0) return;
|
| 849 |
+
|
| 850 |
+
// Hide all containers first
|
| 851 |
+
chartPlaceholder.classList.add('hidden');
|
| 852 |
+
chartCanvas.classList.add('hidden');
|
| 853 |
+
flowchartContainer.classList.add('hidden');
|
| 854 |
+
mindmapContainer.classList.add('hidden');
|
| 855 |
+
|
| 856 |
+
// Get selected values
|
| 857 |
+
const xAxis = xAxisSelect.value;
|
| 858 |
+
const yAxis = yAxisSelect.value;
|
| 859 |
+
const colorScheme = colorSchemeSelect.value;
|
| 860 |
+
const title = chartTitleInput.value || `${currentVizType} Chart`;
|
| 861 |
+
|
| 862 |
+
if (currentVizType === 'bar' || currentVizType === 'line' || currentVizType === 'pie' || currentVizType === 'scatter') {
|
| 863 |
+
// Show chart canvas
|
| 864 |
+
chartCanvas.classList.remove('hidden');
|
| 865 |
+
|
| 866 |
+
// In a real app, we would use a charting library like Chart.js
|
| 867 |
+
// For this demo, we'll just show a placeholder
|
| 868 |
+
const ctx = chartCanvas.getContext('2d');
|
| 869 |
+
|
| 870 |
+
// Clear previous chart if exists
|
| 871 |
+
if (currentChart) {
|
| 872 |
+
currentChart.destroy();
|
| 873 |
+
}
|
| 874 |
+
|
| 875 |
+
// Create mock chart data based on selections
|
| 876 |
+
const labels = currentData.map(item => item[xAxis]);
|
| 877 |
+
const data = currentData.map(item => item[yAxis]);
|
| 878 |
+
|
| 879 |
+
// Generate mock chart
|
| 880 |
+
currentChart = {
|
| 881 |
+
destroy: function() {
|
| 882 |
+
// Mock destroy function
|
| 883 |
+
}
|
| 884 |
+
};
|
| 885 |
+
|
| 886 |
+
// Show a message about what would be rendered
|
| 887 |
+
chartCanvas.width = chartCanvas.offsetWidth;
|
| 888 |
+
chartCanvas.height = chartCanvas.offsetHeight;
|
| 889 |
+
|
| 890 |
+
ctx.fillStyle = '#f8fafc';
|
| 891 |
+
ctx.fillRect(0, 0, chartCanvas.width, chartCanvas.height);
|
| 892 |
+
|
| 893 |
+
ctx.font = '16px Arial';
|
| 894 |
+
ctx.fillStyle = '#334155';
|
| 895 |
+
ctx.textAlign = 'center';
|
| 896 |
+
ctx.fillText(`${title} (${currentVizType})`, chartCanvas.width / 2, 30);
|
| 897 |
+
|
| 898 |
+
ctx.font = '14px Arial';
|
| 899 |
+
ctx.fillText(`X-Axis: ${xAxis}`, chartCanvas.width / 2, 60);
|
| 900 |
+
ctx.fillText(`Y-Axis: ${yAxis}`, chartCanvas.width / 2, 80);
|
| 901 |
+
|
| 902 |
+
// Draw a simple representation of the chart
|
| 903 |
+
if (currentVizType === 'bar') {
|
| 904 |
+
drawMockBarChart(ctx, labels, data);
|
| 905 |
+
} else if (currentVizType === 'line') {
|
| 906 |
+
drawMockLineChart(ctx, labels, data);
|
| 907 |
+
} else if (currentVizType === 'pie') {
|
| 908 |
+
drawMockPieChart(ctx, labels, data);
|
| 909 |
+
} else if (currentVizType === 'scatter') {
|
| 910 |
+
drawMockScatterPlot(ctx, labels, data);
|
| 911 |
+
}
|
| 912 |
+
}
|
| 913 |
+
else if (currentVizType === 'flowchart') {
|
| 914 |
+
// Show flowchart container
|
| 915 |
+
flowchartContainer.classList.remove('hidden');
|
| 916 |
+
|
| 917 |
+
// In a real app, we would use a diagramming library
|
| 918 |
+
flowchartContainer.innerHTML = `
|
| 919 |
+
<div class="text-center p-4">
|
| 920 |
+
<i class="fas fa-project-diagram text-4xl text-blue-500 mb-2"></i>
|
| 921 |
+
<h4 class="text-lg font-medium">Flowchart</h4>
|
| 922 |
+
<p class="text-sm text-gray-600">This would display a flowchart based on your data</p>
|
| 923 |
+
</div>
|
| 924 |
+
`;
|
| 925 |
+
}
|
| 926 |
+
else if (currentVizType === 'mindmap') {
|
| 927 |
+
// Show mindmap container
|
| 928 |
+
mindmapContainer.classList.remove('hidden');
|
| 929 |
+
|
| 930 |
+
// In a real app, we would use a diagramming library
|
| 931 |
+
mindmapContainer.innerHTML = `
|
| 932 |
+
<div class="text-center p-4">
|
| 933 |
+
<i class="fas fa-sitemap text-4xl text-green-500 mb-2"></i>
|
| 934 |
+
<h4 class="text-lg font-medium">Mind Map</h4>
|
| 935 |
+
<p class="text-sm text-gray-600">This would display a mind map based on your data</p>
|
| 936 |
+
</div>
|
| 937 |
+
`;
|
| 938 |
+
}
|
| 939 |
+
}
|
| 940 |
+
|
| 941 |
+
// Draw a mock bar chart (for demo purposes)
|
| 942 |
+
function drawMockBarChart(ctx, labels, data) {
|
| 943 |
+
const maxValue = Math.max(...data);
|
| 944 |
+
const barWidth = 40;
|
| 945 |
+
const startX = 60;
|
| 946 |
+
const startY = 100;
|
| 947 |
+
const chartHeight = ctx.canvas.height - 150;
|
| 948 |
+
const chartWidth = ctx.canvas.width - 120;
|
| 949 |
+
|
| 950 |
+
// Draw axes
|
| 951 |
+
ctx.strokeStyle = '#94a3b8';
|
| 952 |
+
ctx.lineWidth = 1;
|
| 953 |
+
|
| 954 |
+
// Y-axis
|
| 955 |
+
ctx.beginPath();
|
| 956 |
+
ctx.moveTo(startX, startY);
|
| 957 |
+
ctx.lineTo(startX, startY + chartHeight);
|
| 958 |
+
ctx.stroke();
|
| 959 |
+
|
| 960 |
+
// X-axis
|
| 961 |
+
ctx.beginPath();
|
| 962 |
+
ctx.moveTo(startX, startY + chartHeight);
|
| 963 |
+
ctx.lineTo(startX + chartWidth, startY + chartHeight);
|
| 964 |
+
ctx.stroke();
|
| 965 |
+
|
| 966 |
+
// Draw bars
|
| 967 |
+
const spacing = (chartWidth - (labels.length * barWidth)) / (labels.length + 1);
|
| 968 |
+
let x = startX + spacing;
|
| 969 |
+
|
| 970 |
+
for (let i = 0; i < labels.length; i++) {
|
| 971 |
+
const barHeight = (data[i] / maxValue) * chartHeight;
|
| 972 |
+
const y = startY + chartHeight - barHeight;
|
| 973 |
+
|
| 974 |
+
ctx.fillStyle = getBarColor(i);
|
| 975 |
+
ctx.fillRect(x, y, barWidth, barHeight);
|
| 976 |
+
|
| 977 |
+
// Draw label
|
| 978 |
+
ctx.font = '12px Arial';
|
| 979 |
+
ctx.fillStyle = '#334155';
|
| 980 |
+
ctx.textAlign = 'center';
|
| 981 |
+
ctx.fillText(labels[i], x + barWidth/2, startY + chartHeight + 20);
|
| 982 |
+
|
| 983 |
+
x += barWidth + spacing;
|
| 984 |
+
}
|
| 985 |
+
}
|
| 986 |
+
|
| 987 |
+
// Draw a mock line chart (for demo purposes)
|
| 988 |
+
function drawMockLineChart(ctx, labels, data) {
|
| 989 |
+
const maxValue = Math.max(...data);
|
| 990 |
+
const startX = 60;
|
| 991 |
+
const startY = 100;
|
| 992 |
+
const chartHeight = ctx.canvas.height - 150;
|
| 993 |
+
const chartWidth = ctx.canvas.width - 120;
|
| 994 |
+
|
| 995 |
+
// Draw axes
|
| 996 |
+
ctx.strokeStyle = '#94a3b8';
|
| 997 |
+
ctx.lineWidth = 1;
|
| 998 |
+
|
| 999 |
+
// Y-axis
|
| 1000 |
+
ctx.beginPath();
|
| 1001 |
+
ctx.moveTo(startX, startY);
|
| 1002 |
+
ctx.lineTo(startX, startY + chartHeight);
|
| 1003 |
+
ctx.stroke();
|
| 1004 |
+
|
| 1005 |
+
// X-axis
|
| 1006 |
+
ctx.beginPath();
|
| 1007 |
+
ctx.moveTo(startX, startY + chartHeight);
|
| 1008 |
+
ctx.lineTo(startX + chartWidth, startY + chartHeight);
|
| 1009 |
+
ctx.stroke();
|
| 1010 |
+
|
| 1011 |
+
// Draw line
|
| 1012 |
+
ctx.beginPath();
|
| 1013 |
+
ctx.strokeStyle = '#3b82f6';
|
| 1014 |
+
ctx.lineWidth = 2;
|
| 1015 |
+
|
| 1016 |
+
const pointSpacing = chartWidth / (labels.length - 1);
|
| 1017 |
+
let x = startX;
|
| 1018 |
+
|
| 1019 |
+
for (let i = 0; i < labels.length; i++) {
|
| 1020 |
+
const y = startY + chartHeight - (data[i] / maxValue) * chartHeight;
|
| 1021 |
+
|
| 1022 |
+
if (i === 0) {
|
| 1023 |
+
ctx.moveTo(x, y);
|
| 1024 |
+
} else {
|
| 1025 |
+
ctx.lineTo(x, y);
|
| 1026 |
+
}
|
| 1027 |
+
|
| 1028 |
+
// Draw point
|
| 1029 |
+
ctx.fillStyle = '#3b82f6';
|
| 1030 |
+
ctx.beginPath();
|
| 1031 |
+
ctx.arc(x, y, 4, 0, Math.PI * 2);
|
| 1032 |
+
ctx.fill();
|
| 1033 |
+
|
| 1034 |
+
// Draw label
|
| 1035 |
+
ctx.font = '12px Arial';
|
| 1036 |
+
ctx.fillStyle = '#334155';
|
| 1037 |
+
ctx.textAlign = 'center';
|
| 1038 |
+
ctx.fillText(labels[i], x, startY + chartHeight + 20);
|
| 1039 |
+
|
| 1040 |
+
x += pointSpacing;
|
| 1041 |
+
}
|
| 1042 |
+
|
| 1043 |
+
ctx.stroke();
|
| 1044 |
+
}
|
| 1045 |
+
|
| 1046 |
+
// Draw a mock pie chart (for demo purposes)
|
| 1047 |
+
function drawMockPieChart(ctx, labels, data) {
|
| 1048 |
+
const centerX = ctx.canvas.width / 2;
|
| 1049 |
+
const centerY = ctx.canvas.height / 2;
|
| 1050 |
+
const radius = Math.min(ctx.canvas.width, ctx.canvas.height) / 3;
|
| 1051 |
+
const total = data.reduce((sum, value) => sum + value, 0);
|
| 1052 |
+
|
| 1053 |
+
let startAngle = 0;
|
| 1054 |
+
|
| 1055 |
+
for (let i = 0; i < data.length; i++) {
|
| 1056 |
+
const sliceAngle = (data[i] / total) * 2 * Math.PI;
|
| 1057 |
+
|
| 1058 |
+
ctx.fillStyle = getBarColor(i);
|
| 1059 |
+
ctx.beginPath();
|
| 1060 |
+
ctx.moveTo(centerX, centerY);
|
| 1061 |
+
ctx.arc(centerX, centerY, radius, startAngle, startAngle + sliceAngle);
|
| 1062 |
+
ctx.closePath();
|
| 1063 |
+
ctx.fill();
|
| 1064 |
+
|
| 1065 |
+
// Draw label outside
|
| 1066 |
+
const midAngle = startAngle + sliceAngle / 2;
|
| 1067 |
+
const labelX = centerX + (radius + 20) * Math.cos(midAngle);
|
| 1068 |
+
const labelY = centerY + (radius + 20) * Math.sin(midAngle);
|
| 1069 |
+
|
| 1070 |
+
ctx.font = '12px Arial';
|
| 1071 |
+
ctx.fillStyle = '#334155';
|
| 1072 |
+
ctx.textAlign = 'center';
|
| 1073 |
+
ctx.fillText(labels[i], labelX, labelY);
|
| 1074 |
+
|
| 1075 |
+
startAngle += sliceAngle;
|
| 1076 |
+
}
|
| 1077 |
+
}
|
| 1078 |
+
|
| 1079 |
+
// Draw a mock scatter plot (for demo purposes)
|
| 1080 |
+
function drawMockScatterPlot(ctx, labels, data) {
|
| 1081 |
+
const maxValue = Math.max(...data);
|
| 1082 |
+
const startX = 60;
|
| 1083 |
+
const startY = 100;
|
| 1084 |
+
const chartHeight = ctx.canvas.height - 150;
|
| 1085 |
+
const chartWidth = ctx.canvas.width - 120;
|
| 1086 |
+
|
| 1087 |
+
// Draw axes
|
| 1088 |
+
ctx.strokeStyle = '#94a3b8';
|
| 1089 |
+
ctx.lineWidth = 1;
|
| 1090 |
+
|
| 1091 |
+
// Y-axis
|
| 1092 |
+
ctx.beginPath();
|
| 1093 |
+
ctx.moveTo(startX, startY);
|
| 1094 |
+
ctx.lineTo(startX, startY + chartHeight);
|
| 1095 |
+
ctx.stroke();
|
| 1096 |
+
|
| 1097 |
+
// X-axis
|
| 1098 |
+
ctx.beginPath();
|
| 1099 |
+
ctx.moveTo(startX, startY + chartHeight);
|
| 1100 |
+
ctx.lineTo(startX + chartWidth, startY + chartHeight);
|
| 1101 |
+
ctx.stroke();
|
| 1102 |
+
|
| 1103 |
+
// Draw points
|
| 1104 |
+
const pointSpacing = chartWidth / (labels.length - 1);
|
| 1105 |
+
let x = startX;
|
| 1106 |
+
|
| 1107 |
+
for (let i = 0; i < labels.length; i++) {
|
| 1108 |
+
const y = startY + chartHeight - (data[i] / maxValue) * chartHeight;
|
| 1109 |
+
|
| 1110 |
+
ctx.fillStyle = getBarColor(i);
|
| 1111 |
+
ctx.beginPath();
|
| 1112 |
+
ctx.arc(x, y, 6, 0, Math.PI * 2);
|
| 1113 |
+
ctx.fill();
|
| 1114 |
+
|
| 1115 |
+
// Draw label
|
| 1116 |
+
ctx.font = '12px Arial';
|
| 1117 |
+
ctx.fillStyle = '#334155';
|
| 1118 |
+
ctx.textAlign = 'center';
|
| 1119 |
+
ctx.fillText(labels[i], x, startY + chartHeight + 20);
|
| 1120 |
+
|
| 1121 |
+
x += pointSpacing;
|
| 1122 |
+
}
|
| 1123 |
+
}
|
| 1124 |
+
|
| 1125 |
+
// Get color for bars/points based on index and selected color scheme
|
| 1126 |
+
function getBarColor(index) {
|
| 1127 |
+
const scheme = colorSchemeSelect.value;
|
| 1128 |
+
|
| 1129 |
+
const schemes = {
|
| 1130 |
+
default: ['#3b82f6', '#ef4444', '#10b981', '#f59e0b', '#8b5cf6'],
|
| 1131 |
+
rainbow: ['#ff0000', '#ff7f00', '#ffff00', '#00ff00', '#0000ff', '#4b0082', '#9400d3'],
|
| 1132 |
+
pastel: ['#ffb3ba', '#ffdfba', '#ffffba', '#baffc9', '#bae1ff'],
|
| 1133 |
+
warm: ['#ff7b54', '#ffb26b', '#ffd56b', '#939b62', '#416165'],
|
| 1134 |
+
cool: ['#a0e7e5', '#b4f8c8', '#fbe7c6', '#ffaebc', '#aedefc'],
|
| 1135 |
+
monochrome: ['#6b7280', '#9ca3af', '#d1d5db', '#e5e7eb', '#f3f4f6']
|
| 1136 |
+
};
|
| 1137 |
+
|
| 1138 |
+
const colors = schemes[scheme] || schemes.default;
|
| 1139 |
+
return colors[index % colors.length];
|
| 1140 |
+
}
|
| 1141 |
+
|
| 1142 |
+
// Generate AI recommendation
|
| 1143 |
+
function generateAiRecommendation() {
|
| 1144 |
+
if (currentData.length === 0) {
|
| 1145 |
+
alert('Please import data first');
|
| 1146 |
+
return;
|
| 1147 |
+
}
|
| 1148 |
+
|
| 1149 |
+
// In a real app, this would analyze the data structure
|
| 1150 |
+
// For demo, we'll just provide a simple recommendation
|
| 1151 |
+
const headers = Object.keys(currentData[0]);
|
| 1152 |
+
const numericHeaders = headers.filter(h => typeof currentData[0][h] === 'number');
|
| 1153 |
+
const categoricalHeaders = headers.filter(h => typeof currentData[0][h] === 'string');
|
| 1154 |
+
|
| 1155 |
+
let recommendation = '';
|
| 1156 |
+
|
| 1157 |
+
if (numericHeaders.length >= 2 && categoricalHeaders.length >= 1) {
|
| 1158 |
+
recommendation = `A grouped bar chart comparing ${numericHeaders[0]} and ${numericHeaders[1]} across different ${categoricalHeaders[0]} categories would effectively show the relationships in your data.`;
|
| 1159 |
+
} else if (numericHeaders.length >= 1 && categoricalHeaders.length >= 1) {
|
| 1160 |
+
recommendation = `A pie chart showing the distribution of ${numericHeaders[0]} by ${categoricalHeaders[0]} would be a good choice to visualize proportions.`;
|
| 1161 |
+
} else if (numericHeaders.length >= 2) {
|
| 1162 |
+
recommendation = `A scatter plot with ${numericHeaders[0]} on the X-axis and ${numericHeaders[1]} on the Y-axis would help identify correlations.`;
|
| 1163 |
+
} else {
|
| 1164 |
+
recommendation = `Based on your data structure, a simple table might be the most effective way to present this information.`;
|
| 1165 |
+
}
|
| 1166 |
+
|
| 1167 |
+
aiRecommendationText.textContent = recommendation;
|
| 1168 |
+
aiRecommendationSection.classList.remove('hidden');
|
| 1169 |
+
}
|
| 1170 |
+
|
| 1171 |
+
// Apply AI recommendation
|
| 1172 |
+
function applyAiRecommendation() {
|
| 1173 |
+
// In a real app, this would set the appropriate chart type and axes
|
| 1174 |
+
// For demo, we'll just set to bar chart
|
| 1175 |
+
currentVizType = 'bar';
|
| 1176 |
+
chartTypeSelect.value = 'bar';
|
| 1177 |
+
updateVizControls();
|
| 1178 |
+
renderVisualization();
|
| 1179 |
+
|
| 1180 |
+
// Scroll to visualization
|
| 1181 |
+
vizWorkspace.scrollIntoView({ behavior: 'smooth' });
|
| 1182 |
+
}
|
| 1183 |
+
|
| 1184 |
+
// Perform data cleaning action
|
| 1185 |
+
function performDataCleaning(action) {
|
| 1186 |
+
if (currentData.length === 0) {
|
| 1187 |
+
alert('Please import data first');
|
| 1188 |
+
return;
|
| 1189 |
+
}
|
| 1190 |
+
|
| 1191 |
+
switch(action) {
|
| 1192 |
+
case 'remove-duplicates':
|
| 1193 |
+
// In a real app, we would actually remove duplicates
|
| 1194 |
+
alert('Duplicate rows removed successfully!');
|
| 1195 |
+
break;
|
| 1196 |
+
case 'fill-missing':
|
| 1197 |
+
// In a real app, we would fill missing values
|
| 1198 |
+
alert('Missing values filled successfully!');
|
| 1199 |
+
break;
|
| 1200 |
+
case 'filter-data':
|
| 1201 |
+
// In a real app, we would show filtering UI
|
| 1202 |
+
alert('Filter applied successfully!');
|
| 1203 |
+
break;
|
| 1204 |
+
default:
|
| 1205 |
+
alert('Unknown action');
|
| 1206 |
+
}
|
| 1207 |
+
|
| 1208 |
+
// Refresh the preview
|
| 1209 |
+
renderDataPreview();
|
| 1210 |
+
|
| 1211 |
+
// If visualization exists, update it
|
| 1212 |
+
if (!chartPlaceholder.classList.contains('hidden')) {
|
| 1213 |
+
renderVisualization();
|
| 1214 |
+
}
|
| 1215 |
+
}
|
| 1216 |
+
|
| 1217 |
+
// Initialize the app
|
| 1218 |
+
init();
|
| 1219 |
+
</script>
|
| 1220 |
+
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MEDT/dataviz-v2" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
|
| 1221 |
+
</html>
|
prompts.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Hello, I would like to create a data visualization dashboard web app. Here are the key functionalities I need: Allow users to import data from CSV or Excel files. After importing, allow users to select what type of visualization they want to create: Charts (bar, line, pie, scatter, etc.) Diagrams (flowcharts, organizational charts, etc.) Mind Maps Enable drag-and-drop interface for building and customizing visualizations. Provide basic data cleaning options (e.g., remove duplicates, fill missing values). Allow users to filter, sort, and group data before visualization. Enable dynamic updating: if the data changes, the visualization updates automatically. Allow users to customize the visuals (colors, labels, titles, sizes, etc.). Support saving and exporting visualizations (as images or PDFs). Provide dashboard templates for faster setup. Offer an AI assistant suggestion feature: recommend the best type of visualization based on the dataset. Support multi-language UI (optional, but nice to have). The dashboard should have a clean, responsive design that works on desktop and mobile.
|