├── README.md
├── indexedDBScript.js
├── index.html
├── style.css
└── script.js
/README.md:
--------------------------------------------------------------------------------
1 |
Browser Camera App
2 |
3 | Simple Camera App written in HTML, CSS, and JavaScript which can be used to record and capture images.
4 |
5 | Used Technologies
6 |
7 | - HTML5
8 | - CSS3
9 | - JavaScript
10 |
11 |
12 | #### Steps to Use:
13 |
14 | ---
15 |
16 | - Download or clone the repository
17 |
18 | ```
19 | git clone https://github.com/Ayushparikh-code/Web-dev-mini-projects.git
20 | ```
21 |
22 | - Go to the 'Browser Camera' directory
23 | - Run the index.html file
24 | - Start using the camera!!
--------------------------------------------------------------------------------
/indexedDBScript.js:
--------------------------------------------------------------------------------
1 | let request = indexedDB.open("camera", 1);
2 | let db;
3 |
4 | request.onsuccess = function () {
5 | // if exist then will get db from here
6 | db = request.result;
7 | }
8 | request.onerror = function (err) {
9 | console.log(err)
10 | }
11 | request.onupgradeneeded = function () {
12 | // 1st time creation
13 | db = request.result;
14 | db.createObjectStore("images", { keyPath: "mid" });
15 | db.createObjectStore("videos", { keyPath: "mid" });
16 | }
17 |
18 | /* function addMediaToDB(data, table) {
19 | if (db) {
20 | // you need to get transaction
21 | let tx = db.transaction(table, "readwrite");
22 | // get table refer
23 | let store = tx.objectStore(table);
24 | // add
25 | store.add({ mid: Date.now(), media: data });
26 |
27 | } else {
28 | alert("db is loading")
29 | }
30 | } */
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Camera
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | margin: 0;
7 | display: flex;
8 | flex-direction: row;
9 | background-color: black;
10 | }
11 |
12 | .video-container {
13 | height: 100vh;
14 | width: 100vw;
15 | margin: 0 auto;
16 | overflow: hidden;
17 | }
18 |
19 | video {
20 | height: 100%;
21 | width: 100%;
22 | transform: scale(-1, 1);
23 | }
24 |
25 | .filter-container {
26 | position: fixed;
27 | z-index: 2;
28 | justify-self: flex-start;
29 | align-self: center;
30 | left: 5vw;
31 | display: flex;
32 | flex-direction: column;
33 | background-color: white;
34 | }
35 |
36 | .filter {
37 | width: 70px;
38 | height: 50px;
39 | /* Lorem Picsum -> Sample Images */
40 | background-image: url("https://picsum.photos/id/1015/70/50");
41 | background-blend-mode: luminosity;
42 | margin: 1px;
43 | border: black 1px solid;
44 | }
45 |
46 | .filter-1 {
47 | background-color: #cc3838ad;
48 | }
49 | .filter-2 {
50 | background-color: #0fbbbbad;
51 | }
52 | .filter-3 {
53 | background-color: #8ddb18ad;
54 | }
55 | .filter-4 {
56 | background-color: #ee82eead;
57 | }
58 | .filter-5 {
59 | background-color: #b8870bad;
60 | }
61 | .filter-6 {
62 | background-color: #ffffff00;
63 | }
64 |
65 | .ui-filter {
66 | position: fixed;
67 | height: 100vh;
68 | width: 100vw;
69 | z-index: 2;
70 | opacity: 25%;
71 | }
72 |
73 | .timing-container {
74 | position: fixed;
75 | z-index: 2;
76 | justify-self: flex-start;
77 | align-self: flex-end;
78 | left: 5vw;
79 | top: 77vh;
80 | display: flex;
81 | flex-direction: column;
82 | background-color: #00000000;
83 | }
84 |
85 | .timing {
86 | font-size: 1.2rem;
87 | font-weight: 300;
88 | font-family: 'Courier New', Courier, monospace;
89 | color: white;
90 | display: none;
91 | }
92 |
93 | .timing-active {
94 | display: block;
95 | }
96 |
97 | .zoom-container {
98 | position: fixed;
99 | z-index: 2;
100 | justify-self: flex-end;
101 | top: 15vh;
102 | right: 7vw;
103 | display: flex;
104 | flex-direction: column;
105 | border-radius: 5%;
106 | background-color: rgba(61, 54, 54, 0.774);
107 | }
108 |
109 | .fas {
110 | padding: 7px;
111 | color: white;
112 | }
113 |
114 | .button-container {
115 | position: fixed;
116 | z-index: 2;
117 | justify-self: flex-end;
118 | display: flex;
119 | flex-direction: column;
120 | align-self: center;
121 | right: 5vw;
122 | }
123 |
124 | .record, .click {
125 | height: 65px;
126 | width: 65px;
127 | border-radius: 50%;
128 | background-color: #00000000;
129 | border: white solid 5px;
130 | margin: 10px 5px;
131 | }
132 |
133 | #record-video, #click-image {
134 | height: 45px;
135 | width: 45px;
136 | margin: 5px;
137 | border-radius: 50%;
138 | border: #00000000 solid 1px;
139 | font-size: 0.65rem;
140 | }
141 |
142 | #record-video {
143 | background-color: red;
144 | }
145 |
146 | #click-image {
147 | background-color: rgb(216, 216, 216);
148 | }
149 |
150 | .gallery-container {
151 | position: fixed;
152 | z-index: 2;
153 | justify-self: flex-end;
154 | display: flex;
155 | flex-direction: column;
156 | right: 5vw;
157 | bottom: 10vh;
158 | }
159 |
160 | .gallery {
161 | height: 55px;
162 | width: 55px;
163 | background-color: rgba(68, 68, 68, 0.493);
164 | border-radius: 50%;
165 | display: flex;
166 | align-items: center;
167 | justify-content: center;
168 | font-size: 1.45rem;
169 | color: white;
170 | }
171 |
172 | @keyframes buttonAnimation {
173 | 0% {
174 | transform: scale(1);
175 | }
176 | 50% {
177 | transform: scale(0.8);
178 | }
179 | 100% {
180 | transform: scale(1);
181 | }
182 | }
--------------------------------------------------------------------------------
/script.js:
--------------------------------------------------------------------------------
1 | let video = document.querySelector("video");
2 |
3 | let constraints = {
4 | video: true,
5 | audio: true
6 | };
7 |
8 | let mediaRecorder;
9 | let buffer = [];
10 |
11 | let recordState = false;
12 |
13 | let videoRecorder = document.querySelector("#record-video");
14 | let captureButton = document.querySelector("#click-image");
15 |
16 | let timingELem = document.querySelector(".timing");
17 | let clearObj;
18 |
19 | let allFilters = document.querySelectorAll(".filter");
20 | let uiFilter = document.querySelector(".ui-filter");
21 |
22 | let zoomIn = document.querySelector(".fa-plus");
23 | let zoomOut = document.querySelector(".fa-minus");
24 |
25 | let scale = 1.0;
26 |
27 | // Video recorder listeners
28 | navigator.mediaDevices
29 | .getUserMedia(constraints)
30 | .then(function (mediaStream) {
31 | video.srcObject = mediaStream;
32 |
33 | mediaRecorder = new MediaRecorder(mediaStream);
34 | mediaRecorder.addEventListener('dataavailable', function (e) {
35 | buffer.push(e.data);
36 | });
37 | mediaRecorder.addEventListener('stop', function () {
38 | let blob = new Blob(buffer, { type: "video/mp4" });
39 | const url = window.URL.createObjectURL(blob);
40 | let a = document.createElement("a");
41 | a.download = `VID_${getTimeStamp()}.mp4`;
42 | a.href = url;
43 | a.click();
44 | a.remove();
45 | addMediaToDB(url, "videos");
46 | buffer = [];
47 | });
48 | }).catch(function (err) {
49 | console.log(err);
50 | });
51 |
52 | // Recording Video
53 | videoRecorder.addEventListener('click', function () {
54 | if (!mediaRecorder) {
55 | alert("Permissions not given");
56 | return;
57 | }
58 | if (!recordState) {
59 | mediaRecorder.start();
60 | videoRecorder.style.animation = "buttonAnimation 0.75s infinite";
61 | recordState = true;
62 | startClock();
63 | } else {
64 | mediaRecorder.stop();
65 | videoRecorder.style.animation = "none";
66 | recordState = false;
67 | stopClock();
68 | }
69 | });
70 |
71 | // Capturing Image
72 | captureButton.addEventListener("click", function () {
73 | if (!mediaRecorder) {
74 | alert("Permissions not given");
75 | return;
76 | }
77 | // Create a canvas element equal to video frame
78 | let canvas = document.createElement("canvas");
79 | canvas.width = video.videoWidth;
80 | canvas.height = video.videoHeight;
81 | let tool = canvas.getContext("2d");
82 | // Zoom from center
83 | tool.scale(scale, scale);
84 | let x = (tool.canvas.width / scale - video.videoWidth) / 2;
85 | let y = (tool.canvas.height / scale - video.videoHeight) / 2;
86 | // Draw a frame on that canvas
87 | tool.drawImage(video, x, y);
88 | // translucent
89 | tool.globalAlpha = 0.25;
90 | tool.fillStyle = getFilter(document.querySelector(".ui-filter").classList[1]);
91 | // things are drawn on above layer
92 | tool.fillRect(0, 0, canvas.width, canvas.height);
93 | // toDataUrl
94 | let link = canvas.toDataURL();
95 | // Download
96 | let anchor = document.createElement("a");
97 | anchor.href = link;
98 | anchor.download = `IMG_${getTimeStamp()}.png`;
99 | anchor.click();
100 | anchor.remove();
101 | canvas.remove();
102 | addMediaToDB(link, "images");
103 | captureButton.style.animation = "buttonAnimation 0.5s 1";
104 | setTimeout(() => {
105 | captureButton.style.animation = "none";
106 | }, 1000);
107 | });
108 |
109 | // Get current time stamp for file name
110 | function getTimeStamp() {
111 | return new Date().getTime();
112 | }
113 |
114 | // Filter helper
115 | function getFilter(filter) {
116 | switch (filter) {
117 | case "filter-1": return "#cc3838ad";
118 | case "filter-2": return "#0fbbbbad";
119 | case "filter-3": return "#8ddb18ad";
120 | case "filter-4": return "#ee82eead";
121 | case "filter-5": return "#b8870bad";
122 | case "filter-6": return "#ffffff00";
123 | }
124 | }
125 |
126 | // Video Recorder Timers
127 | function startClock() {
128 | timingELem.classList.add("timing-active");
129 | let timeCount = 0;
130 | clearObj = setInterval(function () {
131 | let seconds = (timeCount % 60) < 10 ? `0${timeCount % 60}` : `${timeCount % 60}`;
132 | let minutes = (timeCount / 60) < 10 ? `0${Number.parseInt(timeCount / 60)}` : `${Number.parseInt(timeCount / 60)}`;
133 | let hours = (timeCount / 3600) < 10 ? `0${Number.parseInt(timeCount / 3600)}` : `${Number.parseInt(timeCount / 3600)}`;
134 | timingELem.innerText = `${hours}:${minutes}:${seconds}`;
135 | timeCount++;
136 | }, 1000);
137 | }
138 | function stopClock() {
139 | timingELem.classList.remove("timing-active");
140 | timingELem.innerText = "00:00:00";
141 | clearInterval(clearObj);
142 | }
143 |
144 | // Filter apply
145 | for (let i = 0; i < allFilters.length; i++) {
146 | allFilters[i].addEventListener("click", function () {
147 | uiFilter.classList.remove(uiFilter.classList[1]);
148 | uiFilter.classList.add(allFilters[i].classList[1]);
149 | })
150 | }
151 |
152 | // Zoom apply
153 | zoomIn.addEventListener("click", function () {
154 | if (scale > 1.9)
155 | return;
156 | scale += 0.1;
157 | // -x for mirroring
158 | video.style.transform = `scale(-${scale}, ${scale})`;
159 | })
160 | zoomOut.addEventListener("click", function () {
161 | if (scale < 0.5)
162 | return;
163 | scale -= 0.1;
164 | // -x for mirroring
165 | video.style.transform = `scale(-${scale}, ${scale})`;
166 | })
--------------------------------------------------------------------------------