kopia lustrzana https://github.com/msurguy/SquiggleCam
added brightness and width / height settings
todo: add watchers for brightness, hide the controls somewheremaster
rodzic
b9ed1d6196
commit
35c849dcb9
118
src/App.vue
118
src/App.vue
|
@ -11,8 +11,8 @@
|
|||
<image-chooser @selected="onInputSelected"></image-chooser>
|
||||
|
||||
<div class="image-upload" v-if="this.inputType === 'upload'">
|
||||
<croppa v-model="myCroppa" :width="250" :height="250" :preventWhiteSpace="true" :quality="2"></croppa>
|
||||
<button @click="uploadCroppedImage">Output JPEG</button>
|
||||
<croppa v-model="myCroppa" :width="settings.width/2" :height="settings.height/2" :preventWhiteSpace="true" :quality="2"></croppa>
|
||||
<button class="btn btn-primary btn-block" style="display:block;" @click="uploadCroppedImage">Use Image</button>
|
||||
</div>
|
||||
|
||||
<div class="image-webcam" v-if="this.inputType === 'webcam'">
|
||||
|
@ -52,13 +52,44 @@
|
|||
<circle cx="24" cy="24" r="23" stroke="white" stroke-width="1" fill="#D41616" />
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section-title">
|
||||
Squiggle Controls:
|
||||
</div>
|
||||
|
||||
<div class="slider">
|
||||
<span class="label">
|
||||
Width
|
||||
</span>
|
||||
<input type="range" min="200" max="500" v-model="settings.width">
|
||||
<div class="output">{{ settings.width }}</div>
|
||||
</div>
|
||||
|
||||
<div class="slider">
|
||||
<span class="label">
|
||||
Height
|
||||
</span>
|
||||
<input type="range" min="200" max="500" v-model="settings.height">
|
||||
<div class="output">{{ settings.height }}</div>
|
||||
</div>
|
||||
|
||||
<div class="slider">
|
||||
<span class="label">
|
||||
Min brightness
|
||||
</span>
|
||||
<input type="range" min="0" max="255" v-model="settings.minBrightness">
|
||||
<div class="output">{{ settings.minBrightness }}</div>
|
||||
</div>
|
||||
|
||||
<div class="slider">
|
||||
<span class="label">
|
||||
Max brightness
|
||||
</span>
|
||||
<input type="range" min="0" max="255" v-model="settings.maxBrightness">
|
||||
<div class="output">{{ settings.maxBrightness }}</div>
|
||||
</div>
|
||||
|
||||
<div class="slider">
|
||||
<span class="label">
|
||||
Frequency
|
||||
|
@ -101,15 +132,10 @@
|
|||
Download:
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button class="btn">
|
||||
JPG
|
||||
</button>
|
||||
|
||||
<button class="btn" @click="downloadSVG">
|
||||
SVG
|
||||
</button>
|
||||
<button class="btn">
|
||||
ZIP
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
|
@ -124,9 +150,6 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
// import Navbar from './components/Navbar'
|
||||
// import Loader from './components/Loader'
|
||||
// import Editor from './components/Editor'
|
||||
import ImageChooser from './components/ImageChooser'
|
||||
import WebCam from './components/WebCam'
|
||||
import svgChart from './components/svgChart';
|
||||
|
@ -134,9 +157,6 @@
|
|||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
//cropActions: Navbar ,
|
||||
//loader: Loader,
|
||||
//editor: Editor,
|
||||
imageChooser: ImageChooser,
|
||||
webcam: WebCam,
|
||||
svgChart: svgChart
|
||||
|
@ -172,16 +192,6 @@
|
|||
devices: [],
|
||||
streaming: false
|
||||
},
|
||||
// cropper: {
|
||||
// cropped: false,
|
||||
// cropping: false,
|
||||
// loaded: false,
|
||||
// name: '',
|
||||
// previousUrl: '',
|
||||
// type: '',
|
||||
// url: '',
|
||||
// croppedImageData: ''
|
||||
// },
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -197,12 +207,6 @@
|
|||
this.webcam.deviceId = first.deviceId;
|
||||
}
|
||||
},
|
||||
// 'cropper.croppedImageData': function(){
|
||||
// const canvas = this.cropper.croppedImageData;
|
||||
// const ctx = canvas.getContext("2d");
|
||||
// this.canvasData = ctx.getImageData(0, 0, 500, 500);
|
||||
// return true;
|
||||
// },
|
||||
'settings.frequency': function(){
|
||||
this.processImage();
|
||||
},
|
||||
|
@ -219,13 +223,27 @@
|
|||
|
||||
methods: {
|
||||
downloadSVG(){
|
||||
console.log(this.$refs.svgResult.$el.innerHTML);
|
||||
const svgDoctype = '<?xml version="1.0" standalone="no"?>'
|
||||
+ '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
|
||||
|
||||
// serialize our SVG XML to a string.
|
||||
const svgString = (new XMLSerializer()).serializeToString(this.$refs.svgResult.$el);
|
||||
const blob = new Blob([svgDoctype + svgString], {type: 'image/svg+xml;charset=utf-8'});
|
||||
|
||||
/* This portion of script saves the file to local filesystem as a download */
|
||||
const svgUrl = URL.createObjectURL(blob);
|
||||
const downloadLink = document.createElement("a");
|
||||
downloadLink.href = svgUrl;
|
||||
downloadLink.download = "squiggleCam_" + Date.now() + ".svg";
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
document.body.removeChild(downloadLink);
|
||||
},
|
||||
uploadCroppedImage() {
|
||||
this.myCroppa.generateBlob((blob) => {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = 500;
|
||||
canvas.height = 500;
|
||||
canvas.width = this.settings.width;
|
||||
canvas.height = this.settings.height;
|
||||
// const ctx = canvas.getContext("2d");
|
||||
// this.canvasData = ctx.getImageData(0, 0, 500, 500);
|
||||
|
||||
|
@ -234,7 +252,7 @@
|
|||
|
||||
img.onload = () => {
|
||||
ctx.drawImage(img, 0, 0)
|
||||
this.canvasData = ctx.getImageData(0, 0, 500, 500);
|
||||
this.canvasData = ctx.getImageData(0, 0, this.settings.width, this.settings.height);
|
||||
};
|
||||
|
||||
img.src = URL.createObjectURL(blob);
|
||||
|
@ -246,8 +264,8 @@
|
|||
let config = data.config;
|
||||
// context.getImageData(0, 0, config.WIDTH, config.HEIGHT);
|
||||
let imagePixels = data.image;
|
||||
let width = config.width;
|
||||
let height = config.height;
|
||||
let width = parseInt(config.width);
|
||||
let height = parseInt(config.height);
|
||||
|
||||
// Create some defaults for squiggle-point array
|
||||
let squiggleData = [];
|
||||
|
@ -259,7 +277,7 @@
|
|||
let currentVerticalPixelIndex = 0;
|
||||
let currentHorizontalPixelIndex = 0;
|
||||
let contrastFactor = (259 * (config.contrast + 255)) / (255 * (259 - config.contrast)); // This was established through experiments
|
||||
let horizontalLineSpacing = Math.floor(height/config.lineCount); // Number of pixels to advance in vertical direction
|
||||
let horizontalLineSpacing = Math.floor(height/parseInt(config.lineCount)); // Number of pixels to advance in vertical direction
|
||||
//console.log(horizontalLineSpacing);
|
||||
|
||||
// Iterate line by line (top line to bottom line) in increments of horizontalLineSpacing
|
||||
|
@ -305,9 +323,7 @@
|
|||
|
||||
return squiggleData;
|
||||
}, [{
|
||||
config: {
|
||||
...this.settings
|
||||
},
|
||||
config: Object.assign({}, this.settings),
|
||||
image: this.canvasData
|
||||
}])
|
||||
.then(result => {
|
||||
|
@ -351,24 +367,6 @@
|
|||
this.webcam.camera = deviceId;
|
||||
//console.log("On Camera Change Event", deviceId);
|
||||
},
|
||||
change(action) {
|
||||
const editor = this.$refs.editor;
|
||||
switch (action) {
|
||||
case 'crop':
|
||||
editor.crop();
|
||||
break;
|
||||
case 'clear':
|
||||
editor.clear();
|
||||
break;
|
||||
case 'restore':
|
||||
editor.restore();
|
||||
break;
|
||||
case 'remove':
|
||||
editor.reset();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
},
|
||||
onInputSelected(type) {
|
||||
this.inputType = type;
|
||||
}
|
||||
|
|
|
@ -1,388 +0,0 @@
|
|||
<template>
|
||||
<div class="editor">
|
||||
<div class="canvas" @dblclick="dblclick">
|
||||
<img ref="image" :alt="data.name" :src="data.url" @load="start">
|
||||
</div>
|
||||
<div class="toolbar" v-if="cropper" @click="click">
|
||||
<button class="toolbar__button" data-action="move" title="Move (M)"><span class="fa fa-arrows"></span></button>
|
||||
<button class="toolbar__button" data-action="crop" title="Crop (C)"><span class="fa fa-crop"></span></button>
|
||||
<button class="toolbar__button" data-action="zoom-in" title="Zoom In (I)"><span class="fa fa-search-plus"></span></button>
|
||||
<button class="toolbar__button" data-action="zoom-out" title="Zoom Out (O)"><span class="fa fa-search-minus"></span></button>
|
||||
<button class="toolbar__button" data-action="rotate-left" title="Rotate Left (L)"><span class="fa fa-rotate-left"></span></button>
|
||||
<button class="toolbar__button" data-action="rotate-right" title="Rotate Right (R)"><span class="fa fa-rotate-right"></span></button>
|
||||
<button class="toolbar__button" data-action="flip-horizontal" title="Flip Horizontal (H)"><span class="fa fa-arrows-h"></span></button>
|
||||
<button class="toolbar__button" data-action="flip-vertical" title="Flip Vertical (V)"><span class="fa fa-arrows-v"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Cropper from 'cropperjs';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
canvasData: null,
|
||||
cropBoxData: null,
|
||||
croppedData: null,
|
||||
croppedImageCanvas: null,
|
||||
cropper: null,
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
click({ target }) {
|
||||
const { cropper } = this;
|
||||
const action = target.getAttribute('data-action') || target.parentElement.getAttribute('data-action');
|
||||
|
||||
switch (action) {
|
||||
case 'move':
|
||||
case 'crop':
|
||||
cropper.setDragMode(action);
|
||||
break;
|
||||
|
||||
case 'zoom-in':
|
||||
cropper.zoom(0.1);
|
||||
break;
|
||||
|
||||
case 'zoom-out':
|
||||
cropper.zoom(-0.1);
|
||||
break;
|
||||
|
||||
case 'rotate-left':
|
||||
cropper.rotate(-90);
|
||||
break;
|
||||
|
||||
case 'rotate-right':
|
||||
cropper.rotate(90);
|
||||
break;
|
||||
|
||||
case 'flip-horizontal':
|
||||
cropper.scaleX(-cropper.getData().scaleX || -1);
|
||||
break;
|
||||
|
||||
case 'flip-vertical':
|
||||
cropper.scaleY(-cropper.getData().scaleY || -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
},
|
||||
|
||||
keydown(e) {
|
||||
switch (e.key) {
|
||||
// Undo crop
|
||||
case 'z':
|
||||
if (e.ctrlKey) {
|
||||
e.preventDefault();
|
||||
this.restore();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Delete the image
|
||||
case 'Delete':
|
||||
this.reset();
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
const { cropper } = this;
|
||||
|
||||
if (!cropper) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
// Crop the image
|
||||
case 'Enter':
|
||||
this.crop();
|
||||
break;
|
||||
|
||||
// Clear crop area
|
||||
case 'Escape':
|
||||
this.clear();
|
||||
break;
|
||||
|
||||
// Move to the left
|
||||
case 'ArrowLeft':
|
||||
e.preventDefault();
|
||||
cropper.move(-1, 0);
|
||||
break;
|
||||
|
||||
// Move to the top
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
cropper.move(0, -1);
|
||||
break;
|
||||
|
||||
// Move to the right
|
||||
case 'ArrowRight':
|
||||
e.preventDefault();
|
||||
cropper.move(1, 0);
|
||||
break;
|
||||
|
||||
// Move to the bottom
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
cropper.move(0, 1);
|
||||
break;
|
||||
|
||||
// Enter crop mode
|
||||
case 'c':
|
||||
cropper.setDragMode('crop');
|
||||
break;
|
||||
|
||||
// Enter move mode
|
||||
case 'm':
|
||||
cropper.setDragMode('move');
|
||||
break;
|
||||
|
||||
// Zoom in
|
||||
case 'i':
|
||||
cropper.zoom(0.1);
|
||||
break;
|
||||
|
||||
// Zoom out
|
||||
case 'o':
|
||||
cropper.zoom(-0.1);
|
||||
break;
|
||||
|
||||
// Rotate left
|
||||
case 'l':
|
||||
cropper.rotate(-90);
|
||||
break;
|
||||
|
||||
// Rotate right
|
||||
case 'r':
|
||||
cropper.rotate(90);
|
||||
break;
|
||||
|
||||
// Flip horizontal
|
||||
case 'h':
|
||||
cropper.scaleX(-cropper.getData().scaleX || -1);
|
||||
break;
|
||||
|
||||
// Flip vertical
|
||||
case 'v':
|
||||
cropper.scaleY(-cropper.getData().scaleY || -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
},
|
||||
|
||||
dblclick(e) {
|
||||
if (e.target.className.indexOf('cropper-face') >= 0) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.crop();
|
||||
}
|
||||
},
|
||||
|
||||
start() {
|
||||
const { data } = this;
|
||||
|
||||
if (data.cropped) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cropper = new Cropper(this.$refs.image, {
|
||||
autoCrop: false,
|
||||
dragMode: 'move',
|
||||
background: false,
|
||||
aspectRatio: 1,
|
||||
viewMode: 3,
|
||||
movable: false,
|
||||
data: {
|
||||
width: 500,
|
||||
height: 500
|
||||
},
|
||||
|
||||
|
||||
|
||||
ready: () => {
|
||||
if (this.croppedData) {
|
||||
this.cropper
|
||||
.crop()
|
||||
.setData(this.croppedData)
|
||||
.setCanvasData(this.canvasData)
|
||||
.setCropBoxData(this.cropBoxData);
|
||||
|
||||
this.croppedData = null;
|
||||
this.canvasData = null;
|
||||
this.cropBoxData = null;
|
||||
}
|
||||
this.cropper.setDragMode('crop');
|
||||
},
|
||||
|
||||
crop: ({ detail }) => {
|
||||
const width = detail.width;
|
||||
const height = detail.height;
|
||||
if (width < 500 || height < 500 && data.cropping) {
|
||||
this.cropper.setData({
|
||||
width: 500,
|
||||
height: 500,
|
||||
});
|
||||
}
|
||||
|
||||
if (width > 0 && height > 0 && !data.cropping) {
|
||||
this.update({
|
||||
cropping: true,
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
stop() {
|
||||
if (this.cropper) {
|
||||
this.cropper.destroy();
|
||||
this.cropper = null;
|
||||
//this.croppedImageCanvas = null;
|
||||
//this.
|
||||
}
|
||||
},
|
||||
|
||||
crop() {
|
||||
const { cropper, data } = this;
|
||||
|
||||
if (data.cropping) {
|
||||
this.croppedData = cropper.getData();
|
||||
this.canvasData = cropper.getCanvasData();
|
||||
this.cropBoxData = cropper.getCropBoxData();
|
||||
const croppedCanvas = cropper.getCroppedCanvas(data.type === 'image/png' ? {imageSmoothingQuality: "high", width: 500,
|
||||
height: 500,
|
||||
minWidth: 500,
|
||||
minHeight: 500,
|
||||
maxWidth: 4096,
|
||||
maxHeight: 4096 } : {
|
||||
imageSmoothingQuality: "high",
|
||||
fillColor: '#fff', width: 500,
|
||||
height: 500,
|
||||
minWidth: 500,
|
||||
minHeight: 500,
|
||||
maxWidth: 4096,
|
||||
maxHeight: 4096
|
||||
});
|
||||
this.update({
|
||||
cropped: true,
|
||||
cropping: false,
|
||||
previousUrl: data.url,
|
||||
croppedImageData: croppedCanvas,
|
||||
url: croppedCanvas.toDataURL(data.type),
|
||||
});
|
||||
this.stop();
|
||||
}
|
||||
},
|
||||
|
||||
clear() {
|
||||
if (this.data.cropping) {
|
||||
this.cropper.clear();
|
||||
this.update({
|
||||
cropping: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
restore() {
|
||||
if (this.data.cropped) {
|
||||
this.update({
|
||||
cropped: false,
|
||||
previousUrl: '',
|
||||
url: this.data.previousUrl,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.stop();
|
||||
this.update({
|
||||
cropped: false,
|
||||
cropping: false,
|
||||
loaded: false,
|
||||
name: '',
|
||||
previousUrl: '',
|
||||
type: '',
|
||||
url: '',
|
||||
croppedImageData: ''
|
||||
});
|
||||
},
|
||||
|
||||
update(data) {
|
||||
Object.assign(this.data, data);
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
window.addEventListener('keydown', (this.onKeydown = this.keydown.bind(this)));
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('keydown', this.onKeydown);
|
||||
this.stop();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.editor {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.canvas {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
|
||||
& > img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
bottom: 1rem;
|
||||
color: #fff;
|
||||
height: 2rem;
|
||||
left: 50%;
|
||||
margin-left: -8rem;
|
||||
position: absolute;
|
||||
width: 16rem;
|
||||
z-index: 2015;
|
||||
}
|
||||
|
||||
.toolbar__button {
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
float: left;
|
||||
font-size: .875rem;
|
||||
height: 2rem;
|
||||
text-align: center;
|
||||
width: 2rem;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #0074d9;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,106 +0,0 @@
|
|||
<template>
|
||||
<div class="loader" @change="change" @dragover="dragover" @drop="drop">
|
||||
<p>Drop image here or
|
||||
<label class="browse">browse...
|
||||
<input class="sr-only" id="file" type="file" accept="image/*">
|
||||
</label>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const URL = window.URL || window.webkitURL;
|
||||
|
||||
export default {
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
read(files) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!files || files.length === 0) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const file = files[0];
|
||||
|
||||
if (/^image\/\w+$/.test(file.type)) {
|
||||
if (URL) {
|
||||
resolve({
|
||||
loaded: true,
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
url: URL.createObjectURL(file),
|
||||
});
|
||||
} else {
|
||||
reject(new Error('Your browser is not supported.'));
|
||||
}
|
||||
} else {
|
||||
reject(new Error('Please choose an image file.'));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
change({ target }) {
|
||||
this.read(target.files).then((data) => {
|
||||
target.value = '';
|
||||
this.update(data);
|
||||
}).catch((e) => {
|
||||
target.value = '';
|
||||
this.alert(e);
|
||||
});
|
||||
},
|
||||
|
||||
dragover(e) {
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
drop(e) {
|
||||
e.preventDefault();
|
||||
this.read(e.dataTransfer.files).catch(this.alert);
|
||||
},
|
||||
|
||||
alert(e) {
|
||||
window.alert(e && e.message ? e.message : e);
|
||||
},
|
||||
|
||||
update(data) {
|
||||
Object.assign(this.data, data);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.loader {
|
||||
border: 2px #666666 dashed;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.browse {
|
||||
color: #0074d9;
|
||||
cursor: pointer;
|
||||
margin-left: .25rem;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
border: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
width: 1px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -1,76 +0,0 @@
|
|||
<template>
|
||||
<div class="navbar">
|
||||
<nav class="nav" @click="click">
|
||||
<button type="button" class="nav__button" data-action="restore" title="Undo (Ctrl + Z)" v-if="data.cropped"><span class="fa fa-undo"></span></button>
|
||||
<button type="button" class="nav__button nav__button--danger" data-action="remove" title="Delete (Delete)" v-if="data.loaded && !data.cropping"><span class="fa fa-trash"></span></button>
|
||||
<button type="button" class="nav__button nav__button--danger" data-action="clear" title="Cancel (Esc)" v-if="data.cropping"><span class="fa fa-ban"></span></button>
|
||||
<button type="button" class="nav__button nav__button--success" data-action="crop" title="OK (Enter)" v-if="data.cropping"><span class="fa fa-check"></span></button>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
downloadable: typeof document.createElement('a').download !== 'undefined',
|
||||
};
|
||||
},
|
||||
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
click({ target }) {
|
||||
const action = target.getAttribute('data-action') || target.parentElement.getAttribute('data-action');
|
||||
|
||||
if (action) {
|
||||
this.$emit('change', action);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.navbar {
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav__button {
|
||||
background-color: transparent;
|
||||
border-width: 0;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
float: left;
|
||||
height: 3rem;
|
||||
line-height: 3rem;
|
||||
text-align: center;
|
||||
width: 3rem;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #0074d9;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.nav--success:hover {
|
||||
background-color: #2ecc40;
|
||||
}
|
||||
|
||||
.nav--danger:hover {
|
||||
background-color: #ff4136;
|
||||
}
|
||||
</style>
|
|
@ -137,8 +137,8 @@
|
|||
}
|
||||
// Emit video start/live event
|
||||
this.$refs.video.onloadedmetadata = () => {
|
||||
this.width = 500;
|
||||
this.height = 500;
|
||||
// this.width = 500;
|
||||
// this.height = 500;
|
||||
|
||||
this.$emit("video-live", stream);
|
||||
};
|
||||
|
@ -191,6 +191,7 @@
|
|||
* load the Camera passed as index!
|
||||
*/
|
||||
loadCamera(device) {
|
||||
console.log('loading camera, width', this.width);
|
||||
navigator.mediaDevices
|
||||
.getUserMedia({
|
||||
video: {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<svg :view-box.camel="viewbox" :width="width" :height="height">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" :view-box.camel="viewbox" :width="width" :height="height">
|
||||
<g>
|
||||
<svg-chart-line :d="line" :o="options" v-for="(line, index) in lines" :key="index"></svg-chart-line>
|
||||
</g>
|
||||
|
@ -21,11 +21,3 @@
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
path {
|
||||
fill: none;
|
||||
stroke: #0f0f0f;
|
||||
stroke-width: 1.5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<path :d="pathD"></path>
|
||||
<path :d="pathD" style="stroke-width: 1.5px; fill: none; stroke: #000000;"></path>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -86,6 +86,11 @@ html [type="button"] {
|
|||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||
}
|
||||
|
||||
.btn-block {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-circle {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
|
|
Ładowanie…
Reference in New Issue