JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://fonts.googleapis.com/css?family=Cinzel|Monsieur+La+Doulaise|Tangerine"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
<div class="container">
<div class="row">
<div class="col-md-2">
<button type="file" class="btn btn-dark btn-sm" id="upload_link">New Photo</button>
<br>
<input type="file" id="file" /><a href="" id="upload_link" hidden>Add Photo</a>
<div class="btn-group">
<button class="btn btn-dark btn-sm dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Choose your...</button>
<div class="dropdown-menu">
<!-- <h6 class="dropdown-header">Theme</h6>
<a onclick="replaceImage(oImg2, 'images/themes/none.png')" class="dropdown-item">None</a>
<a onclick="replaceImage(oImg2, 'images/themes/beach.png')" class="dropdown-item">Beach</a>
<div class="dropdown-divider"></div> -->
<h6 class="dropdown-header">Frame</h6>
<a onclick="replaceImage(oImg, 'images/frames/LightBrownWoodOval.png')" class="dropdown-item">Oval Light Brown</a>
<a onclick="replaceImage(oImg, 'images/frames/MidToneWoodFrameOval.png')" class="dropdown-item">Oval Mid Tone Wood</a>
<a onclick="replaceImage(oImg, 'images/frames/SilverFrameOval.png')" class="dropdown-item">Oval Silver</a>
<a onclick="replaceImage(oImg, 'images/frames/DistressedWhiteFrameRec.png')"...
CSS
a.dropdown-item {
cursor: pointer;
}
.btn {
margin-top: 10px;
cursor: pointer;
}
canvas {
border: 1px solid #dddddd;
border-radius: 4px;
margin: 10px 0px 0px 12px;
cursor: pointer;
}
/* Styling the upload link */
#upload_link {
text-decoration: none;
}
#file {
display: none;
}
JavaScript
var canvas = new fabric.Canvas('c');
var oImg, oImg2, isImageLoaded;
//initialize default frame (light brown wood oval)
fabric.Image.fromURL('https://i.imgur.com/DrzSWSa.png', function(img) {
isImageLoaded = true;
oImg = img.set({
selectable: false,
}).scale(0.5);
canvas.add(oImg).renderAll();
canvas.sendToBack(oImg);
});
//initialize some text
canvas.add(new fabric.IText('Some Text', {
left: 475,
top: 25,
fontFamily: 'Monsieur La Doulaise',
fontSize: 27,
hasBorders: false,
hasControls: false,
selectable: true,
lockRotation: true,
lockMovementX: true,
lockMovementY: true,
align: 'mid',
originX: 'center',
originY: 'center',
centeredScaling: true,
}));
//initialize Some More Text
canvas.add(new fabric.IText('Some More Text', {
left: 475,
top: 60,
fontFamily: 'cinzel',
fontSize: 27,
hasBorders: false,
hasControls: false,
selectable: true,
lockRotation: true,
lockMovementX: true,
lockMovementY: true,
align: 'mid',
originX: 'center',
originY: 'center',
centeredScaling: true,
}));
//oImgObj bread and butter, kudos @grunt
function replaceImage(oImgObj, imgUrl) {
if (!isImageLoaded) return; //return if initial image not loaded
var imgElem = oImgObj._element; //reference to actual image element
imgElem.src = imgUrl; //set image source
imgElem.onload = () => canvas.renderAll(); //render on image load
}
// Download canvas as image
$("#d").click(function() {
$("#c").get(0).toBlob(function(blob) {
saveAs(blob, "memorialportrait.jpg");
});
});
// Upload an image to the canvas
document.getElementById('file').addEventListener("change", function(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function(f) {
var data = f.target.result;
fabric.Image.fromURL(data, function(img) {
var oImg = img.set({
left: 400,
top: 102
}).scale(.8);
canvas.add(oImg);
canvas.setActiveObject(oImg);
var image =...