<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->
<!DOCTYPE html><html class=''>
<head><script src='//production-assets.codepen.io/assets/editor/live/console_runner-079c09a0e3b9ff743e39ee2d5637b9216b3545af0de366d4b9aad9dc87e26bfd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/events_runner-73716630c22bbc8cff4bd0f07b135f00a0bdc5d14629260c3ec49e5606f98fdd.js'></script><script src='//production-assets.codepen.io/assets/editor/live/css_live_reload_init-2c0dc5167d60a5af3ee189d570b1835129687ea2a61bee3513dee3a50c115a77.js'></script><meta charset='UTF-8'><meta name="robots" content="noindex"><link rel="shortcut icon" type="image/x-icon" href="//production-assets.codepen.io/assets/favicon/favicon-8ea04875e70c4b0bb41da869e81236e54394d63638a1ef12fa558a4a835f1164.ico" /><link rel="mask-icon" type="" href="//production-assets.codepen.io/assets/favicon/logo-pin-f2d2b6d2c61838f7e76325261b7195c27224080bc099486ddd6dccb469b8e8e6.svg" color="#111" /><link rel="canonical" href="https://codepen.io/dannyrb/pen/ZLWVBq" />
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,700" rel="stylesheet">
<link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css'>
<style class="cp-pen-styles">/*******************************
* HTML5 Canvas Image Uploader
*******************************/
/* Trickery to allow hidden input, but get around safety checks by browsers */
.image-input__input {
position: absolute;
top: -10px;
left: -10px;
width: 9px;
height: 9px;
cursor: pointer;
}
.image-input__container {
position: absolute;
overflow: hidden;
border: 1px dashed #FFF;
box-sizing: border-box;
/* display border inside */
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.image-input__container:hover {
border: 1px solid #7FCC29;
-webkit-transition: 0.15s border;
transition: 0.15s border;
background: url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/424395/camera.svg");
background-size: 50px 41px;
background-position: center;
background-repeat: no-repeat;
}
.image-input__overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.image-loaded .image-input__overlay {
display: none;
}
.image-input__control-buttons {
display: none;
position: absolute;
top: 5px;
left: 5px;
}
.image-loaded .image-input__control-buttons {
display: block;
}
.image-input__control-buttons button {
margin: 0;
padding: 0;
width: 25px;
height: 25px;
}
.image-input__canvas.is-draggable {
cursor: move;
}
/*******************************
* Demo Styles
*******************************/
body {
color: #FFF;
background-color: #533A71;
font-family: 'Roboto', sans-serif;
}
h1 {
margin-bottom: 0;
}
.sub {
font-style: italic;
font-weight: 300;
}
.app-container {
margin: 0 auto;
min-width: 650px;
max-width: 800px;
}
#app {
position: relative;
}
.image-uploader {
position: absolute;
margin: 20px 10px;
left: 0;
}
.text-area-section {
position: absolute;
margin: 20px 10px;
padding: 0;
width: 300px;
height: 200px;
overflow: hidden;
right: 0;
}
textarea {
width: 100%;
height: 100%;
}
</style></head><body>
<main class="app-container">
<h1>VueJS + HTML5 Canvas</h1>
<span class="sub">Image upload, resize, crop, and base64 converter</span>
<div id="app">
<image-uploader
width="300px"
height="200px">
</image-uploader>
<section class="text-area-section">
<textarea
v-model="sharedData.imageData">
</textarea>
</section>
</div>
</main>
<!-- -->
<script type="text/x-template" id="image-uploader-template">
<div class="image-input__container image-uploader"
v-bind:style="containerStyles"
v-bind:class="{ 'image-loaded': isImageLoaded }">
<!-- Hidden input we use to access file contents -->
<form class="image-input__form" ref="form">
<input @change="previewThumbnail" class="image-input__input" ref="fileInput" type="file" />
</form>
<div v-on:click="triggerInput" class="image-input__overlay"></div>
<div class="image-input__control-buttons">
<button v-on:click="toBase64" type="button" class="to-base64">64</button>
<button v-on:click="scaleUp" type="button" class="scale-up">+</button>
<button v-on:click="scaleDown" type="button" class="scale-down">-</button>
<button v-on:click="resetInput" type="button" class="reset-input">x</button>
</div>
<!-- Used in place of an image tag -->
<canvas class="image-input__canvas"
ref="canvas"
v-bind:height="height"
v-bind:width="width"
v-bind:class="{ 'is-draggable': hoverIsDraggable }">
</canvas>
</div>
</script>
<script src='//production-assets.codepen.io/assets/common/stopExecutionOnTimeout-b2a7b3fe212eaa732349046d8416e00a9dec26eb7fd347590fbced3ab38af52e.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.5/vue.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/vue-router/2.0.1/vue-router.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/vue-resource/1.0.3/vue-resource.min.js'></script><script src='https://cdnjs.cloudflare.com/ajax/libs/vuex/2.0.0/vuex.js'></script>
<script >'use strict';
var sharedData = {
imageData: '',
updateImageData: function updateImageData(newData) {
this.imageData = newData;
}
};
Vue.component('image-uploader', {
template: '#image-uploader-template',
props: ['id', 'width', 'height'],
// Must be a function in component definition
data: function data() {
return {
isImageLoaded: false,
hoverIsDraggable: false,
// Image
ctx: null, canvas: null,
img: null,
// Properties
scaleSteps: 0,
imageX: 0, imageY: 0,
scaledImageWidth: 0, scaledImageHeight: 0,
imageWidth: 0, imageHeight: 0, imageRight: 0, imageBottom: 0,
// State
draggingImage: false,
// Mouse
startX: 0, startY: 0,
mouseX: 0, mouseY: 0,
sharedData: window.sharedData
};
},
computed: {
containerStyles: function containerStyles() {
return {
width: this.width,
height: this.height
};
}
},
mounted: function mounted() {
this.$on('get-image-base64', function () {
console.log("ON'ING");
this.updateTemplateImage();
});
// Instantiate
this.canvas = this.$refs.canvas;
this.ctx = this.canvas.getContext("2d");
this.img = document.createElement("img");
},
methods: {
toBase64: function toBase64() {
var imageData = this.canvas.toDataURL("image/png");
imageData.replace('data:image/png;base64,', '');
this.sharedData.updateImageData(imageData);
},
draw: function draw(withBorders) {
// clear the canvas
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// some maths
var scaleFactor = 1 - this.scaleSteps * .1;
this.scaledImageWidth = this.img.width * scaleFactor;
this.scaledImageHeight = this.scaledImageWidth * (this.img.height / this.img.width);
// draw the image
// this.ctx.drawImage(
// this.img, (top left coords of source to use (x,y)),
// width & height of source to use (width, height)
// (x,y) on canvas
// width & height on canvas
this.ctx.drawImage(this.img, 0, 0, this.img.width, this.img.height, this.imageX, this.imageY, this.scaledImageWidth, this.scaledImageHeight);
this.imageRight = this.imageX + this.scaledImageWidth;
this.imageBottom = this.imageY + this.scaledImageHeight;
// optionally draw a box around the image (indicates "selected")
if (withBorders) {
this.ctx.beginPath();
this.ctx.moveTo(this.imageX, this.imageY);
this.ctx.lineTo(this.imageRight, this.imageY);
this.ctx.lineTo(this.imageRight, this.imageBottom);
this.ctx.lineTo(this.imageX, this.imageBottom);
this.ctx.closePath();
this.ctx.stroke();
}
},
resetInput: function resetInput() {
// clear the canvas
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Reset state
this.$refs.form.reset();
this.isImageLoaded = false;
},
scaleUp: function scaleUp() {
this.scaleSteps--;
this.draw(false);
},
scaleDown: function scaleDown() {
this.scaleSteps++;
this.draw(false);
},
getMousePos: function getMousePos(evt) {
var rect = this.canvas.getBoundingClientRect(),
// abs. size of element
scaleX = this.canvas.width / rect.width,
// relationship bitmap vs. element for X
scaleY = this.canvas.height / rect.height; // relationship bitmap vs. element for Y
return {
x: (evt.clientX - rect.left) * scaleX, // scale mouse coordinates after they have
y: (evt.clientY - rect.top) * scaleY // been adjusted to be relative to element
};
},
isImageHit: function isImageHit(x, y) {
return x > this.imageX && x < this.imageX + this.imageWidth && y > this.imageY && y < this.imageY + this.imageHeight;
},
triggerInput: function triggerInput(event) {
event.preventDefault();
this.$refs.fileInput.click();
},
previewThumbnail: function previewThumbnail(event) {
var vm = this;
var input = event.target;
if (input.files && input.files[0]) {
var reader = new FileReader();
// Set as source
reader.onload = function (e) {
vm.img.src = e.target.result;
};
reader.readAsDataURL(input.files[0]);
vm.img.onload = function () {
// Draw
vm.ctx.drawImage(vm.img, 0, 0);
// Grab position info
vm.imageWidth = vm.img.width;
vm.imageHeight = vm.img.height;
vm.imageRight = vm.imageX + vm.imageWidth;
vm.imageBottom = vm.imageY + vm.imageHeight;
// Update CTX
vm.draw(false);
// Notify component
vm.isImageLoaded = true;
};
}
function handleMouseDown(e) {
var pos = vm.getMousePos(e);
vm.startX = pos.x;
vm.startY = pos.y;
vm.draggingImage = vm.hoverIsDraggable;
}
function handleMouseUp(e) {
vm.draggingImage = false;
vm.draw(false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
// Update cursor property var (;
var pos = vm.getMousePos(e);
vm.hoverIsDraggable = vm.isImageHit(pos.x, pos.y);
if (vm.draggingImage) {
//
vm.mouseX = pos.x;
vm.mouseY = pos.y;
// move the image by the amount of the latest drag
var dx = vm.mouseX - vm.startX;
var dy = vm.mouseY - vm.startY;
// Lock image to canvas viewport
var collidedOnLeft = vm.imageX > 0 && dx > 0;
var collidedOnRight = vm.imageRight < vm.canvas.width && dx < 0;
var collidedOnTop = vm.imageY > 0 && dy > 0;
var collidedOnBottom = vm.imageBottom < vm.canvas.height && dy < 0;
if (collidedOnLeft) {
vm.imageX = 0;
vm.imageRight = vm.scaledImageWidth;
} else if (collidedOnRight) {
vm.imageX = vm.canvas.width - vm.scaledImageWidth;
vm.imageRight = vm.canvas.width;
} else {
vm.imageX += dx;
vm.imageRight += dx;
}
if (collidedOnTop) {
vm.imageY = 0;
vm.imageBottom = vm.scaledImageHeight;
} else if (collidedOnBottom) {
vm.imageY = vm.canvas.height - vm.scaledImageHeight;
vm.imageBottom = vm.canvas.height;
} else {
vm.imageY += dy;
vm.imageBottom += dy;
}
// Reset the startXY for next time
vm.startX = vm.mouseX;
vm.startY = vm.mouseY;
// Redraw the image with border
vm.draw(true);
}
} // END MOUSEMOVE
// LISTEN (:
vm.canvas.addEventListener('mousedown', handleMouseDown, false);
vm.canvas.addEventListener('mousemove', handleMouseMove, false);
vm.canvas.addEventListener('mouseup', handleMouseUp, false);
vm.canvas.addEventListener('mouseout', handleMouseOut, false);
}
}
});
var app = new Vue({
el: '#app',
data: {
sharedData: window.sharedData
},
methods: {}
});
//# sourceURL=pen.js
</script>
</body></html>