kopia lustrzana https://github.com/msurguy/SquiggleCam
switched to Croppa
rodzic
5e6789fc5c
commit
b9ed1d6196
|
@ -1622,6 +1622,11 @@
|
||||||
"integrity": "sha512-ogq4NbUWf1uG/j66k0AmiO3GjqJAlQyF8n4w8a954cbCyFKmYGvRtgz6qkq2fWuduTXHibX7GyYL5Pg58Aks2g==",
|
"integrity": "sha512-ogq4NbUWf1uG/j66k0AmiO3GjqJAlQyF8n4w8a954cbCyFKmYGvRtgz6qkq2fWuduTXHibX7GyYL5Pg58Aks2g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"canvas-exif-orientation": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/canvas-exif-orientation/-/canvas-exif-orientation-0.4.0.tgz",
|
||||||
|
"integrity": "sha1-tIfzcBmYqeh56xBAELKlgRU2i2s="
|
||||||
|
},
|
||||||
"caseless": {
|
"caseless": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||||
|
@ -10974,6 +10979,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.5.21.tgz",
|
"resolved": "https://registry.npmjs.org/vue/-/vue-2.5.21.tgz",
|
||||||
"integrity": "sha512-Aejvyyfhn0zjVeLvXd70h4hrE4zZDx1wfZqia6ekkobLmUZ+vNFQer53B4fu0EjWBSiqApxPejzkO1Znt3joxQ=="
|
"integrity": "sha512-Aejvyyfhn0zjVeLvXd70h4hrE4zZDx1wfZqia6ekkobLmUZ+vNFQer53B4fu0EjWBSiqApxPejzkO1Znt3joxQ=="
|
||||||
},
|
},
|
||||||
|
"vue-croppa": {
|
||||||
|
"version": "1.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-croppa/-/vue-croppa-1.3.8.tgz",
|
||||||
|
"integrity": "sha512-WwYgEKscTCD7BzhnbfRJfzWIU6RcMq2JRimB3aI5gGzpADmpKuqmDh9+oVfiZaEnpmRthgXZxcAvbxU6CeIU9w==",
|
||||||
|
"requires": {
|
||||||
|
"canvas-exif-orientation": "^0.4.0",
|
||||||
|
"object-assign": "^4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"vue-hot-reload-api": {
|
"vue-hot-reload-api": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.1.tgz",
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"pica": "^5.0.0",
|
"pica": "^5.0.0",
|
||||||
"vue": "^2.5.2",
|
"vue": "^2.5.2",
|
||||||
|
"vue-croppa": "^1.3.8",
|
||||||
"vue-worker": "^1.2.1"
|
"vue-worker": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
115
src/App.vue
115
src/App.vue
|
@ -11,8 +11,8 @@
|
||||||
<image-chooser @selected="onInputSelected"></image-chooser>
|
<image-chooser @selected="onInputSelected"></image-chooser>
|
||||||
|
|
||||||
<div class="image-upload" v-if="this.inputType === 'upload'">
|
<div class="image-upload" v-if="this.inputType === 'upload'">
|
||||||
<loader v-if="!cropper.loaded" ref="loader" :data="cropper"></loader>
|
<croppa v-model="myCroppa" :width="250" :height="250" :preventWhiteSpace="true" :quality="2"></croppa>
|
||||||
<crop-actions v-if="cropper.loaded" :data="cropper" @change="change"></crop-actions>
|
<button @click="uploadCroppedImage">Output JPEG</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="image-webcam" v-if="this.inputType === 'webcam'">
|
<div class="image-webcam" v-if="this.inputType === 'webcam'">
|
||||||
|
@ -102,24 +102,21 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button class="btn">
|
<button class="btn">
|
||||||
PNG
|
JPG
|
||||||
</button>
|
</button>
|
||||||
<button class="btn">
|
<button class="btn" @click="downloadSVG">
|
||||||
SVG
|
SVG
|
||||||
</button>
|
</button>
|
||||||
<button class="btn">
|
<button class="btn">
|
||||||
ZIP
|
ZIP
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-toggle">
|
|
||||||
<button id="panelToggler" class="btn"><span class="fa fa-chevron-left"></span></button>
|
|
||||||
</div>
|
|
||||||
</aside>
|
</aside>
|
||||||
<main>
|
<main>
|
||||||
<div v-if="canvasData" class="svg-container" style="padding: 10px;" ref="container">
|
<div v-if="canvasData" class="svg-container" style="padding: 10px;" ref="container">
|
||||||
<svg-chart :lines="lines" :options="line" :width="settings.width" :height="settings.height"></svg-chart>
|
<svg-chart ref="svgResult" :lines="lines" :options="line" :width="settings.width" :height="settings.height"></svg-chart>
|
||||||
</div>
|
</div>
|
||||||
<editor v-if="cropper.loaded" ref="editor" :data="cropper"></editor>
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -127,9 +124,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Navbar from './components/Navbar'
|
// import Navbar from './components/Navbar'
|
||||||
import Loader from './components/Loader'
|
// import Loader from './components/Loader'
|
||||||
import Editor from './components/Editor'
|
// import Editor from './components/Editor'
|
||||||
import ImageChooser from './components/ImageChooser'
|
import ImageChooser from './components/ImageChooser'
|
||||||
import WebCam from './components/WebCam'
|
import WebCam from './components/WebCam'
|
||||||
import svgChart from './components/svgChart';
|
import svgChart from './components/svgChart';
|
||||||
|
@ -137,15 +134,17 @@
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
cropActions: Navbar ,
|
//cropActions: Navbar ,
|
||||||
loader: Loader,
|
//loader: Loader,
|
||||||
editor: Editor,
|
//editor: Editor,
|
||||||
imageChooser: ImageChooser,
|
imageChooser: ImageChooser,
|
||||||
webcam: WebCam,
|
webcam: WebCam,
|
||||||
svgChart: svgChart
|
svgChart: svgChart
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
myCroppa: {},
|
||||||
|
dataUrl: '',
|
||||||
line: {
|
line: {
|
||||||
smoothing: 0.25,
|
smoothing: 0.25,
|
||||||
flattening: 0.5
|
flattening: 0.5
|
||||||
|
@ -173,16 +172,16 @@
|
||||||
devices: [],
|
devices: [],
|
||||||
streaming: false
|
streaming: false
|
||||||
},
|
},
|
||||||
cropper: {
|
// cropper: {
|
||||||
cropped: false,
|
// cropped: false,
|
||||||
cropping: false,
|
// cropping: false,
|
||||||
loaded: false,
|
// loaded: false,
|
||||||
name: '',
|
// name: '',
|
||||||
previousUrl: '',
|
// previousUrl: '',
|
||||||
type: '',
|
// type: '',
|
||||||
url: '',
|
// url: '',
|
||||||
croppedImageData: ''
|
// croppedImageData: ''
|
||||||
},
|
// },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -198,12 +197,12 @@
|
||||||
this.webcam.deviceId = first.deviceId;
|
this.webcam.deviceId = first.deviceId;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'cropper.croppedImageData': function(){
|
// 'cropper.croppedImageData': function(){
|
||||||
const canvas = this.cropper.croppedImageData;
|
// const canvas = this.cropper.croppedImageData;
|
||||||
const ctx = canvas.getContext("2d");
|
// const ctx = canvas.getContext("2d");
|
||||||
this.canvasData = ctx.getImageData(0, 0, 500, 500);
|
// this.canvasData = ctx.getImageData(0, 0, 500, 500);
|
||||||
return true;
|
// return true;
|
||||||
},
|
// },
|
||||||
'settings.frequency': function(){
|
'settings.frequency': function(){
|
||||||
this.processImage();
|
this.processImage();
|
||||||
},
|
},
|
||||||
|
@ -219,6 +218,28 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
downloadSVG(){
|
||||||
|
console.log(this.$refs.svgResult.$el.innerHTML);
|
||||||
|
},
|
||||||
|
uploadCroppedImage() {
|
||||||
|
this.myCroppa.generateBlob((blob) => {
|
||||||
|
let canvas = document.createElement("canvas");
|
||||||
|
canvas.width = 500;
|
||||||
|
canvas.height = 500;
|
||||||
|
// const ctx = canvas.getContext("2d");
|
||||||
|
// this.canvasData = ctx.getImageData(0, 0, 500, 500);
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
let img = new Image();
|
||||||
|
|
||||||
|
img.onload = () => {
|
||||||
|
ctx.drawImage(img, 0, 0)
|
||||||
|
this.canvasData = ctx.getImageData(0, 0, 500, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
img.src = URL.createObjectURL(blob);
|
||||||
|
}, 'image/jpeg', 1)
|
||||||
|
},
|
||||||
processImage() {
|
processImage() {
|
||||||
this.$worker.run((data) => {
|
this.$worker.run((data) => {
|
||||||
// Gather all necessary data from the main thread
|
// Gather all necessary data from the main thread
|
||||||
|
@ -252,7 +273,7 @@
|
||||||
// starting pixel for each line will be this
|
// starting pixel for each line will be this
|
||||||
|
|
||||||
// Loop through pixels from left to right within the current line, advancing by increments of config.SPACING
|
// Loop through pixels from left to right within the current line, advancing by increments of config.SPACING
|
||||||
console.log(config.spacing, width);
|
//console.log(config.spacing, width);
|
||||||
for (let x = config.spacing; x < width; x += config.spacing ) {
|
for (let x = config.spacing; x < width; x += config.spacing ) {
|
||||||
|
|
||||||
currentHorizontalPixelIndex = x + currentVerticalPixelIndex; // Get array position of current pixel
|
currentHorizontalPixelIndex = x + currentVerticalPixelIndex; // Get array position of current pixel
|
||||||
|
@ -358,21 +379,21 @@
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import './styles/index.scss';
|
@import './styles/index.scss';
|
||||||
|
|
||||||
.cropper-header {
|
/*.cropper-header {*/
|
||||||
background-color: #666;
|
/*background-color: #666;*/
|
||||||
height: 3rem;
|
/*height: 3rem;*/
|
||||||
overflow: hidden;
|
/*overflow: hidden;*/
|
||||||
padding-left: 1rem;
|
/*padding-left: 1rem;*/
|
||||||
padding-right: 1rem;
|
/*padding-right: 1rem;*/
|
||||||
position: relative;
|
/*position: relative;*/
|
||||||
z-index: 1;
|
/*z-index: 1;*/
|
||||||
}
|
/*}*/
|
||||||
@media (min-width: 768px) {
|
/*@media (min-width: 768px) {*/
|
||||||
.cropper-header {
|
/*.cropper-header {*/
|
||||||
padding-left: 1.5rem;
|
/*padding-left: 1.5rem;*/
|
||||||
padding-right: 1.5rem;
|
/*padding-right: 1.5rem;*/
|
||||||
}
|
/*}*/
|
||||||
}
|
/*}*/
|
||||||
.title {
|
.title {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
<div class="button-group stretch">
|
<div class="button-group stretch">
|
||||||
<label>Input:</label>
|
<label>Input:</label>
|
||||||
<button id="upload" :disabled="disabled" v-bind:class="{ active: selectedItem === 'upload' }" class="btn" @click="toggle">File</button>
|
<button id="upload" :disabled="disabled" v-bind:class="{ active: selectedItem === 'upload' }" class="btn" @click="toggle">File</button>
|
||||||
<!--<button id="url" :disabled="disabled" v-bind:class="{ active: selectedItem === 'url' }" class="btn" @click="toggle">URL</button>-->
|
|
||||||
<button id="webcam" :disabled="disabled" class="btn" v-bind:class="{ active: selectedItem === 'webcam' }" @click="toggle">WebCam</button>
|
<button id="webcam" :disabled="disabled" class="btn" v-bind:class="{ active: selectedItem === 'webcam' }" @click="toggle">WebCam</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<template>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "ImageTransformer"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<template>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "SquiggleDataRetriever"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -1,13 +0,0 @@
|
||||||
<template>
|
|
||||||
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "SquiggleRenderer"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -23,5 +23,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
path {
|
||||||
|
fill: none;
|
||||||
|
stroke: #0f0f0f;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<path :style="styles.path" :d="pathD"></path>
|
<path :d="pathD"></path>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -9,15 +9,6 @@
|
||||||
name: "svgChartLine",
|
name: "svgChartLine",
|
||||||
props: ["d", "o"],
|
props: ["d", "o"],
|
||||||
computed: {
|
computed: {
|
||||||
styles() {
|
|
||||||
return {
|
|
||||||
path: {
|
|
||||||
fill: 'none',
|
|
||||||
stroke: "#000",
|
|
||||||
strokeWidth: 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
pathD() {
|
pathD() {
|
||||||
return this.pointsPositions.reduce((acc, e, i, a) => i === 0
|
return this.pointsPositions.reduce((acc, e, i, a) => i === 0
|
||||||
? `M ${e[0]},${e[1]}`
|
? `M ${e[0]},${e[1]}`
|
||||||
|
@ -45,20 +36,16 @@
|
||||||
const flat = lib.map(Math.cos(o.angle) * this.o.flattening, 0, 1, 1, 0)
|
const flat = lib.map(Math.cos(o.angle) * this.o.flattening, 0, 1, 1, 0)
|
||||||
const angle = o.angle * flat + (reverse ? Math.PI : 0);
|
const angle = o.angle * flat + (reverse ? Math.PI : 0);
|
||||||
const length = o.length * this.o.smoothing;
|
const length = o.length * this.o.smoothing;
|
||||||
const x = current[0] + Math.cos(angle) * length;
|
const x = Math.round((current[0] + Math.cos(angle) * length) * 100) / 100 ;
|
||||||
const y = current[1] + Math.sin(angle) * length;
|
const y = Math.round((current[1] + Math.sin(angle) * length) * 100) / 100 ;
|
||||||
return [x, y];
|
return [x, y];
|
||||||
},
|
},
|
||||||
bezierCommand(point, i, a) {
|
bezierCommand(point, i, a) {
|
||||||
const cps = this.controlPoint(a[i - 1], a[i - 2], point);
|
const cps = this.controlPoint(a[i - 1], a[i - 2], point);
|
||||||
const cpe = this.controlPoint(point, a[i - 1], a[i + 1], true);
|
const cpe = this.controlPoint(point, a[i - 1], a[i + 1], true);
|
||||||
//const close = i === a.length - 1 ? " z" : "";
|
//const close = i === a.length - 1 ? " z" : "";
|
||||||
return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`;
|
return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${Math.round(point[0] * 100) / 100},${Math.round(point[1]*100)/100}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
11
src/main.js
11
src/main.js
|
@ -4,13 +4,18 @@ import 'normalize.css'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './App'
|
import App from './App'
|
||||||
import VueWorker from 'vue-worker';
|
import VueWorker from 'vue-worker';
|
||||||
|
import Croppa from 'vue-croppa'
|
||||||
|
|
||||||
//import './styles/index.scss'
|
//import './styles/index.scss'
|
||||||
import 'cropperjs/dist/cropper.css';
|
//import 'cropperjs/dist/cropper.css';
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
import 'vue-croppa/dist/vue-croppa.css'
|
||||||
|
|
||||||
|
|
||||||
|
Vue.config.productionTip = false;
|
||||||
|
|
||||||
Vue.use(VueWorker);
|
Vue.use(VueWorker);
|
||||||
|
Vue.use(Croppa);
|
||||||
|
|
||||||
|
|
||||||
/* eslint-disable no-new */
|
/* eslint-disable no-new */
|
||||||
|
@ -18,4 +23,4 @@ new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
components: { App },
|
components: { App },
|
||||||
template: '<App/>'
|
template: '<App/>'
|
||||||
})
|
});
|
||||||
|
|
|
@ -344,25 +344,6 @@ input[type="range"]:focus::-ms-fill-upper {
|
||||||
align-content: space-between;
|
align-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-toggle {
|
|
||||||
position: absolute;
|
|
||||||
right: -12px;
|
|
||||||
bottom: 50px;
|
|
||||||
z-index: 1;
|
|
||||||
//align-self: center;
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
z-index: 100;
|
|
||||||
background-color: #000;
|
|
||||||
padding: 20px 0;
|
|
||||||
}
|
|
||||||
.btn:hover {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #0069d9;
|
|
||||||
border-color: #0062cc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-webcam {
|
.image-webcam {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue