kopia lustrzana https://github.com/msurguy/SquiggleCam
added CSS back into SVG output, added credits
rodzic
4844c7dae3
commit
6084654601
492
src/App.vue
492
src/App.vue
|
@ -9,6 +9,43 @@
|
|||
</div>
|
||||
|
||||
<div class="accordion">
|
||||
<div class="option">
|
||||
<input type="checkbox" id="toggle2" class="toggle" />
|
||||
<label class="title" for="toggle2">Paper Settings</label>
|
||||
|
||||
<div class="content">
|
||||
<div class="paper-chooser">
|
||||
<div class="button-group stretch">
|
||||
<label>Color:</label>
|
||||
<button v-bind:class="{ active: settings.black === false }" class="btn" @click="settings.black = false">White</button>
|
||||
<button class="btn" v-bind:class="{ active: settings.black === true }" @click="settings.black = true">Black</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="slider">
|
||||
<span class="metric">
|
||||
{{widthInCM}}cm
|
||||
</span>
|
||||
<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="metric">
|
||||
{{widthInCM}}cm
|
||||
</span>
|
||||
<span class="label">
|
||||
Height
|
||||
</span>
|
||||
<input type="range" min="200" max="500" v-model="settings.height">
|
||||
<div class="output">{{ settings.height }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<input type="checkbox" checked id="toggle1" class="toggle" />
|
||||
<label class="title" for="toggle1">
|
||||
|
@ -76,27 +113,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<input type="checkbox" id="toggle2" class="toggle" />
|
||||
<label class="title" for="toggle2">Paper Settings</label>
|
||||
<div class="content">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<input type="checkbox" id="toggle3" class="toggle" />
|
||||
|
@ -172,7 +188,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section-title">
|
||||
|
@ -184,10 +199,17 @@
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div class="credits">
|
||||
<p>
|
||||
Project by <a target="_blank" href="http://twitter.com/msurguy">@msurguy</a>
|
||||
<br>Source on <span class="fa fa-github"></span><a href="http://github.com/msurguys/SquiggleCam">Github</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
<main>
|
||||
<div v-if="canvasData" class="svg-container" style="padding: 10px; overflow: visible" ref="container">
|
||||
<svg-chart ref="svgResult" :lines="lines" :width="settings.width" :height="settings.height"></svg-chart>
|
||||
<div v-if="canvasData" class="svg-container" ref="container">
|
||||
<svg-chart ref="svgResult" :black="settings.black" :lines="lines" :width="settings.width" :height="settings.height"></svg-chart>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
@ -201,234 +223,248 @@
|
|||
import svgChart from './components/svgChart';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
imageChooser: ImageChooser,
|
||||
webcam: WebCam,
|
||||
svgChart: svgChart
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
cropper: {},
|
||||
dataUrl: '',
|
||||
lines: [],
|
||||
inputType: "upload",
|
||||
settings: {
|
||||
frequency: 150,
|
||||
amplitude: 1,
|
||||
lineCount: 50,
|
||||
brightness: 0,
|
||||
contrast: 0,
|
||||
minBrightness: 0,
|
||||
maxBrightness: 255,
|
||||
spacing: 1,
|
||||
width: 500,
|
||||
height: 500
|
||||
},
|
||||
canvasData: null,
|
||||
webcam: {
|
||||
img: null,
|
||||
camera: null,
|
||||
deviceId: null,
|
||||
device: null,
|
||||
devices: [],
|
||||
streaming: false
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
'webcam.camera': function(id) {
|
||||
this.webcam.deviceId = id;
|
||||
name: 'App',
|
||||
components: {
|
||||
imageChooser: ImageChooser,
|
||||
webcam: WebCam,
|
||||
svgChart: svgChart
|
||||
},
|
||||
'webcam.devices': function() {
|
||||
// Once we have a list select the first one
|
||||
let first = this.webcam.devices[0];
|
||||
if (first) {
|
||||
this.webcam.camera = first.deviceId;
|
||||
this.webcam.deviceId = first.deviceId;
|
||||
data() {
|
||||
return {
|
||||
cropper: {},
|
||||
dataUrl: '',
|
||||
lines: [],
|
||||
inputType: "upload",
|
||||
settings: {
|
||||
black: false,
|
||||
frequency: 150,
|
||||
amplitude: 1,
|
||||
lineCount: 50,
|
||||
brightness: 0,
|
||||
contrast: 0,
|
||||
minBrightness: 0,
|
||||
maxBrightness: 255,
|
||||
spacing: 1,
|
||||
width: 500,
|
||||
height: 500
|
||||
},
|
||||
canvasData: null,
|
||||
webcam: {
|
||||
img: null,
|
||||
camera: null,
|
||||
deviceId: null,
|
||||
device: null,
|
||||
devices: [],
|
||||
streaming: false
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
'webcam.camera': function(id) {
|
||||
this.webcam.deviceId = id;
|
||||
},
|
||||
'webcam.devices': function() {
|
||||
// Once we have a list select the first one
|
||||
let first = this.webcam.devices[0];
|
||||
if (first) {
|
||||
this.webcam.camera = first.deviceId;
|
||||
this.webcam.deviceId = first.deviceId;
|
||||
}
|
||||
},
|
||||
'settings.frequency': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.spacing': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.lineCount': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.amplitude': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.minBrightness': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.maxBrightness': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.brightness': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.contrast': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.black': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'canvasData': function(){
|
||||
this.processImage();
|
||||
}
|
||||
},
|
||||
'settings.frequency': function(){
|
||||
this.processImage();
|
||||
computed: {
|
||||
widthInCM(){
|
||||
return Math.round(10*this.settings.width / 38)/10;
|
||||
},
|
||||
heightInCM(){
|
||||
return Math.round(10*this.settings.height / 38)/10;
|
||||
}
|
||||
},
|
||||
'settings.spacing': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.lineCount': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.amplitude': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.minBrightess': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.maxBrightness': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.brightness': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'settings.contrast': function(){
|
||||
this.processImage();
|
||||
},
|
||||
'canvasData': function(){
|
||||
this.processImage();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
downloadSVG(){
|
||||
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">';
|
||||
|
||||
methods: {
|
||||
downloadSVG(){
|
||||
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'});
|
||||
|
||||
// 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.cropper.generateBlob((blob) => {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = this.settings.width;
|
||||
canvas.height = this.settings.height;
|
||||
|
||||
/* 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.cropper.generateBlob((blob) => {
|
||||
let canvas = document.createElement("canvas");
|
||||
canvas.width = this.settings.width;
|
||||
canvas.height = this.settings.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
let img = new Image();
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
let img = new Image();
|
||||
img.onload = () => {
|
||||
ctx.drawImage(img, 0, 0)
|
||||
this.canvasData = ctx.getImageData(0, 0, this.settings.width, this.settings.height);
|
||||
};
|
||||
|
||||
img.onload = () => {
|
||||
ctx.drawImage(img, 0, 0)
|
||||
this.canvasData = ctx.getImageData(0, 0, this.settings.width, this.settings.height);
|
||||
};
|
||||
|
||||
img.src = URL.createObjectURL(blob);
|
||||
}, 'image/jpeg', 1)
|
||||
},
|
||||
processImage() {
|
||||
this.$worker.run((data) => {
|
||||
// Gather all necessary data from the main thread
|
||||
let config = data.config;
|
||||
img.src = URL.createObjectURL(blob);
|
||||
}, 'image/jpeg', 1)
|
||||
},
|
||||
processImage() {
|
||||
this.$worker.run((data) => {
|
||||
// Gather all necessary data from the main thread
|
||||
let config = data.config;
|
||||
// context.getImageData(0, 0, config.WIDTH, config.HEIGHT);
|
||||
const imagePixels = data.image;
|
||||
const width = parseInt(config.width);
|
||||
const height = parseInt(config.height);
|
||||
const contrast = parseInt(config.contrast);
|
||||
const brightness = parseInt(config.brightness);
|
||||
const lineCount = parseInt(config.lineCount);
|
||||
const minBrightness = parseInt(config.minBrightness);
|
||||
const maxBrightness = parseInt(config.maxBrightness);
|
||||
const spacing = parseFloat(config.spacing);
|
||||
const imagePixels = data.image;
|
||||
const width = parseInt(config.width);
|
||||
const height = parseInt(config.height);
|
||||
const contrast = parseInt(config.contrast);
|
||||
const brightness = parseInt(config.brightness);
|
||||
const lineCount = parseInt(config.lineCount);
|
||||
const minBrightness = parseInt(config.minBrightness);
|
||||
const maxBrightness = parseInt(config.maxBrightness);
|
||||
const spacing = parseFloat(config.spacing);
|
||||
const black = config.black;
|
||||
|
||||
// Create some defaults for squiggle-point array
|
||||
let squiggleData = [];
|
||||
let r = 5;
|
||||
let a = 0;
|
||||
let b;
|
||||
let z;
|
||||
let currentLine = []; // create empty array for storing x,y coordinate pairs
|
||||
let currentVerticalPixelIndex = 0;
|
||||
let currentHorizontalPixelIndex = 0;
|
||||
let contrastFactor = (259 * (contrast + 255)) / (255 * (259 - contrast)); // This was established through experiments
|
||||
let horizontalLineSpacing = Math.floor(height / lineCount); // Number of pixels to advance in vertical direction
|
||||
//console.log(horizontalLineSpacing);
|
||||
let squiggleData = [];
|
||||
let r = 5;
|
||||
let a = 0;
|
||||
let b;
|
||||
let z;
|
||||
let currentLine = []; // create empty array for storing x,y coordinate pairs
|
||||
let currentVerticalPixelIndex = 0;
|
||||
let currentHorizontalPixelIndex = 0;
|
||||
let contrastFactor = (259 * (contrast + 255)) / (255 * (259 - contrast)); // This was established through experiments
|
||||
let horizontalLineSpacing = Math.floor(height / lineCount); // Number of pixels to advance in vertical direction
|
||||
|
||||
// Iterate line by line (top line to bottom line) in increments of horizontalLineSpacing
|
||||
//let tmpCounter = 0;
|
||||
for (let y = 0; y < height; y+= horizontalLineSpacing) {
|
||||
a = 0;
|
||||
currentLine = [];
|
||||
currentLine.push([0, y]); // Start the line
|
||||
//let tmpCounter = 0;
|
||||
for (let y = 0; y < height; y+= horizontalLineSpacing) {
|
||||
a = 0;
|
||||
currentLine = [];
|
||||
currentLine.push([0, y]); // Start the line
|
||||
|
||||
currentVerticalPixelIndex = y*width; // Because Image Pixel array is of length width * height,
|
||||
// starting pixel for each line will be this
|
||||
currentVerticalPixelIndex = y*width; // Because Image Pixel array is of length width * height,
|
||||
// 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
|
||||
//console.log(config.spacing, width);
|
||||
for (let x = spacing; x < width; x += spacing ) {
|
||||
// Loop through pixels from left to right within the current line, advancing by increments of config.SPACING
|
||||
//console.log(config.spacing, width);
|
||||
for (let x = spacing; x < width; x += spacing ) {
|
||||
|
||||
currentHorizontalPixelIndex = Math.floor(x + currentVerticalPixelIndex); // Get array position of current pixel
|
||||
currentHorizontalPixelIndex = Math.floor(x + currentVerticalPixelIndex); // Get array position of current pixel
|
||||
|
||||
// When there is contrast adjustment, the calculations of brightness values are a bit different
|
||||
if (contrast !== 0) {
|
||||
// Determine how bright a pixel is, from 0 to 255 by summing three channels (R,G,B) multiplied by some coefficients
|
||||
b = (0.2125 * ((contrastFactor * (imagePixels.data[4 * currentHorizontalPixelIndex] - 128) + 128 )
|
||||
+ brightness)) + (0.7154 * ((contrastFactor * (imagePixels.data[4 * (currentHorizontalPixelIndex + 1)] - 128) + 128)
|
||||
+ brightness)) + (0.0721 * ((contrastFactor*(imagePixels.data[4*(currentHorizontalPixelIndex+2)]-128)+128) + brightness));
|
||||
} else {
|
||||
b = (0.2125 * (imagePixels.data[4*currentHorizontalPixelIndex] + brightness)) + (0.7154 * (imagePixels.data[4*(currentHorizontalPixelIndex + 1)]+ brightness)) + (0.0721 * (imagePixels.data[4*(currentHorizontalPixelIndex + 2)] + brightness));
|
||||
// When there is contrast adjustment, the calculations of brightness values are a bit different
|
||||
if (contrast !== 0) {
|
||||
// Determine how bright a pixel is, from 0 to 255 by summing three channels (R,G,B) multiplied by some coefficients
|
||||
b = (0.2125 * ((contrastFactor * (imagePixels.data[4 * currentHorizontalPixelIndex] - 128) + 128 )
|
||||
+ brightness)) + (0.7154 * ((contrastFactor * (imagePixels.data[4 * (currentHorizontalPixelIndex + 1)] - 128) + 128)
|
||||
+ brightness)) + (0.0721 * ((contrastFactor*(imagePixels.data[4*(currentHorizontalPixelIndex+2)]-128)+128) + brightness));
|
||||
} else {
|
||||
b = (0.2125 * (imagePixels.data[4*currentHorizontalPixelIndex] + brightness)) + (0.7154 * (imagePixels.data[4*(currentHorizontalPixelIndex + 1)]+ brightness)) + (0.0721 * (imagePixels.data[4*(currentHorizontalPixelIndex + 2)] + brightness));
|
||||
}
|
||||
|
||||
if (black) {
|
||||
b = Math.min(255-minBrightness,255-b); // Set minimum line curvature to value set by the user
|
||||
z = Math.max(maxBrightness-b,0); // Set maximum line curvature to value set by the user
|
||||
} else {
|
||||
b = Math.max(minBrightness,b); // Set minimum line curvature to value set by the user
|
||||
z = Math.max(maxBrightness-b,0); // Set maximum line curvature to value set by the user
|
||||
}
|
||||
|
||||
// The magic of the script, determines how high / low the squiggle goes
|
||||
r = config.amplitude * z / lineCount;
|
||||
|
||||
a += z / config.frequency;
|
||||
currentLine.push([x,y + Math.sin(a)*r]);
|
||||
}
|
||||
|
||||
b = Math.max(minBrightness,b); // Set minimum line curvature to value set by the user
|
||||
z = Math.max(maxBrightness-b,0); // Set maximum line curvature to value set by the user
|
||||
|
||||
// The magic of the script, determines how high / low the squiggle goes
|
||||
r = config.amplitude * z / lineCount;
|
||||
|
||||
a += z / config.frequency;
|
||||
currentLine.push([x,y + Math.sin(a)*r]);
|
||||
//currentLine.push([config.width, y]);
|
||||
squiggleData.push(currentLine);
|
||||
}
|
||||
//currentLine.push([config.width, y]);
|
||||
squiggleData.push(currentLine);
|
||||
}
|
||||
|
||||
return squiggleData;
|
||||
}, [{
|
||||
config: Object.assign({}, this.settings),
|
||||
image: this.canvasData
|
||||
}])
|
||||
.then(result => {
|
||||
this.lines = [];
|
||||
|
||||
result.forEach( line => {
|
||||
this.lines.push({values: line});
|
||||
return squiggleData;
|
||||
}, [{
|
||||
config: Object.assign({}, this.settings),
|
||||
image: this.canvasData
|
||||
}])
|
||||
.then(result => {
|
||||
this.lines = [];
|
||||
result.forEach( line => {
|
||||
this.lines.push({values: line});
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
},
|
||||
onCapture() {
|
||||
this.webcam.img = this.$refs.webcam.capture();
|
||||
this.canvasData = this.$refs.webcam.getCanvasRaw();
|
||||
},
|
||||
onStarted(stream) {
|
||||
this.webcam.streaming = true;
|
||||
},
|
||||
onStopped(stream) {
|
||||
this.webcam.streaming = false;
|
||||
},
|
||||
onStop() {
|
||||
this.$refs.webcam.stop();
|
||||
},
|
||||
onStart() {
|
||||
this.$refs.webcam.start();
|
||||
},
|
||||
onError(error) {
|
||||
//console.log("On Error Event", error);
|
||||
},
|
||||
onCameras(cameras) {
|
||||
this.webcam.devices = cameras;
|
||||
//console.log("On Cameras Event", cameras);
|
||||
},
|
||||
onCameraChange(deviceId) {
|
||||
this.webcam.deviceId = deviceId;
|
||||
this.webcam.camera = deviceId;
|
||||
//console.log("On Camera Change Event", deviceId);
|
||||
},
|
||||
onInputSelected(type) {
|
||||
this.inputType = type;
|
||||
.catch(e => {
|
||||
console.error(e)
|
||||
})
|
||||
},
|
||||
onCapture() {
|
||||
this.webcam.img = this.$refs.webcam.capture();
|
||||
this.canvasData = this.$refs.webcam.getCanvasRaw();
|
||||
},
|
||||
onStarted(stream) {
|
||||
this.webcam.streaming = true;
|
||||
},
|
||||
onStopped(stream) {
|
||||
this.webcam.streaming = false;
|
||||
},
|
||||
onStop() {
|
||||
this.$refs.webcam.stop();
|
||||
},
|
||||
onStart() {
|
||||
this.$refs.webcam.start();
|
||||
},
|
||||
onError(error) {
|
||||
console.log("On Error Event", error);
|
||||
},
|
||||
onCameras(cameras) {
|
||||
this.webcam.devices = cameras;
|
||||
console.log("On Cameras Event", cameras);
|
||||
},
|
||||
onCameraChange(deviceId) {
|
||||
this.webcam.deviceId = deviceId;
|
||||
this.webcam.camera = deviceId;
|
||||
},
|
||||
onInputSelected(type) {
|
||||
this.inputType = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" :view-box.camel="viewbox" :width="width" :height="height">
|
||||
<svg :style="{ background: background}" xmlns="http://www.w3.org/2000/svg" :view-box.camel="viewbox" :width="width" :height="height">
|
||||
<g>
|
||||
<svg-chart-line :d="line" v-for="(line, index) in lines" :key="index"></svg-chart-line>
|
||||
<svg-chart-line :d="line" :stroke="stroke" v-for="(line, index) in lines" :key="index"></svg-chart-line>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
|
@ -13,11 +13,25 @@
|
|||
components: {
|
||||
svgChartLine
|
||||
},
|
||||
props: ["lines", "options","width","height"],
|
||||
props: ["lines", "black","width","height"],
|
||||
computed: {
|
||||
viewbox() {
|
||||
return `0 0 ${this.width} ${this.height}`;
|
||||
},
|
||||
background(){
|
||||
return this.black ? '#000000' : '#FFFFFF'
|
||||
},
|
||||
stroke(){
|
||||
return {
|
||||
color: this.black ? '#FFFFFF' : '#000000',
|
||||
fill: 'none',
|
||||
width: '2px'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
<template>
|
||||
<path :d="pathD" style="stroke-width: 1.5px; fill: none; stroke: #000000;"></path>
|
||||
<path v-bind:style="{strokeWidth: stroke.width, fill: stroke.fill, stroke: stroke.color}" :d="pathD"></path>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "svgChartLine",
|
||||
props: ["d"],
|
||||
props: ["d", "stroke"],
|
||||
computed: {
|
||||
pathD() {
|
||||
let path = "";
|
||||
|
||||
this.d.values.forEach((point, index) => {
|
||||
if (index === 0) {
|
||||
path += `M ${point[0]},${point[1]}`;
|
||||
|
|
|
@ -12,6 +12,10 @@ body {
|
|||
color: #d2d2d2;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #298bff;
|
||||
}
|
||||
|
||||
.btn:not(:disabled):not(.disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -173,19 +177,31 @@ aside {
|
|||
background-image: linear-gradient(-90deg, #2e2e2e 0%, #353535 100%);
|
||||
box-shadow: 0 0 5px 0 #0f0f0f;
|
||||
flex: 0 0 270px;
|
||||
transform: translate(0px, 0px);
|
||||
//transform: translate(0px, 0px);
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
transition: transform 0.3s ease-in-out;
|
||||
|
||||
&.hidden {
|
||||
transform: translate(-300px, 0);
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
//height: 100%;
|
||||
//min-height: ;
|
||||
//transition: transform 0.3s ease-in-out;
|
||||
//
|
||||
//&.hidden {
|
||||
// transform: translate(-300px, 0);
|
||||
//}
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
position: -webkit-sticky; /* Safari */
|
||||
position: sticky;
|
||||
top: 0;
|
||||
align-self: flex-start;
|
||||
|
||||
.svg-container {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="range"] {
|
||||
|
@ -324,11 +340,22 @@ input[type="range"]:focus::-ms-fill-upper {
|
|||
font-size: 12px;
|
||||
color: #d2d2d2;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.metric {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
line-height: 18px;
|
||||
left: 0;
|
||||
font-family: Monaco, monospace;
|
||||
font-size: 12px;
|
||||
color: #d2d2d2;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input[type="range"] {
|
||||
margin-top: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
.output {
|
||||
margin-top: 28px;
|
||||
|
@ -418,9 +445,13 @@ input[type="range"]:focus::-ms-fill-upper {
|
|||
|
||||
.toggle:checked {
|
||||
& + .title + .content {
|
||||
max-height: 500px;
|
||||
max-height: 600px;
|
||||
}
|
||||
& + .title:before {
|
||||
transform: rotate(135deg) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.credits {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue