Adding Text on the selected canvas in Fabric js - javascript

I have fabric js multiple canvases and I would like to add Text on the selected canvas, instead of the last item of the array.
If a user creates multiple canvases then I need an option to add the text on the selected canvas.
Please run the code snippet or see the codepen demo of the current approach...
Thank you!
//================== Create Canvas start =================
var createCanvas = document.getElementById("createCanvas");
var canvasInstances = [];
createCanvas.addEventListener('click',function(){
var canvasContainer = document.getElementById("canvasContainer");
var newcanvas = document.createElement("canvas");
//newcanvas.classList.add("active");
canvasContainer.append(newcanvas);
var fabricCanvasObj = new fabric.Canvas(newcanvas, {
height: 400,
width: 400,
backgroundColor: '#ffffff',
});
canvasInstances.push(fabricCanvasObj);
console.log(canvasInstances);
})
//================== Create Canvas End =================
//================== Add Text ================
var addText = document.getElementById("addText");
addText.addEventListener('click',function(){
canvasInstances.forEach(function(current,id,array){
if(id === array.length - 1){
const converText = new fabric.IText(`Type Text`,{
type: 'text',
width: 200,
fontSize: 20,
left: 20,
top: 20,
fill: '#444'
});
current.add(converText);
current.renderAll();
return false;
}
})
})
//================== Add End =================
*{
box-sizing: border-box;
}
body{
background:#ccc;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 200px;
}
.canvas-container{
margin-bottom:10px;
}
.add-text{
margin: 20px;
width: 400px;
text-align: center;
border:1px dashed red;
padding: 15px;
cursor:pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script>
<div class="add-text" id="addText">Add Text</div>
<div id="canvasContainer">
</div>
<button id="createCanvas">Create Canvas</button>

Declare canvasobject globally, you can try below code
<script type="text/javascript">
var canvasobject;
window.onload = function () {
canvasobject = new fabric.Canvas('myCanvas');
canvasobject.backgroundColor = '#0056d6';
canvasobject.renderAll();
//
function addtext() {
var textvalue = "Type here";
var fontcolor = "#333";
var fontFamily = "Baloo 2";
var myfont = new FontFaceObserver(fontFamily);
myfont.load()
.then(function () {
// when font is loaded, use it.
var text = new fabric.Text(textvalue, {
left: 100,
top: 100,
fontFamily: fontFamily,
fill: fontcolor,
});
canvasobject.add(text);
canvasobject.renderAll();
}).catch(function (e) {
//console.log(e);
console.log('font loading failed ' + fontFamily);
});
}
}

Related

Add element using javascript at specific position

I'm creating a small game to use in one of my English classes. I've managed to add all the items and create the animations of the items.
What I need now is to place the items in their fixed and starting positions. The blue and red items have their fixed positions at the bottom corner of each side and the soccerball starts in the middle before any movement.
I don't know how to do this. Can anybody help me or point me in the right direction, please.
This is what I have now:
This is what I would like to do:
This is my code so far
<script>
//Set Background
document.body.style.backgroundImage =
"url('./back.jpg')";
document.body.style.backgroundSize = 'contain';
document.body.style.backgroundRepeat = 'no-repeat';
document.body.style.backgroundPosition = 'center';
document.body.style.backgroundSize = '100%';
//Add images
function show_image(src, width, height, alt, id) {
var img = document.createElement("img");
img.src = src;
img.width = width;
img.height = height;
img.alt = alt;
img.id = id;
if (id == "s") {
img.style.position = "center"
}
document.body.appendChild(img);
}
show_image("./b.png", 100, 100, "btnBlue", "b")
show_image("./r.png", 100, 100, "btnRed", "r")
show_image("./s.png", 100, 100, "btnSoccerBall", "s")
//Add onclick
document.getElementById("b").addEventListener("click", myMoveLeft);
document.getElementById("r").addEventListener("click", myMoveRight);
//Add animation
var item = document.getElementById('s');
var anim;
var x = 0, y = 0;
function myMoveLeft() {
anim = item.animate([
// keyframes
{ transform: `translate(${x}px, ${y}px)` },
{ transform: `translate(${x - 60}px, ${y}px)` }
], {
duration: 1000,
iterations: 1,
fill: 'forwards'
});
x -= 60;
}
function myMoveRight() {
anim = item.animate([
// keyframes
{ transform: `translate(${x}px, ${y}px)` },
{ transform: `translate(${x + 60}px, ${y}px)` }
], {
duration: 1000,
iterations: 1,
fill: 'forwards'
});
x += 60;
}
item.addEventListener('animationend', () => {
console.log('Animation ended');
});
</script>
I think what you want to achieve can be done with CSS, specifically by using Flexbox.
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 5rem;
}
.btnBlue {
color: blue;
}
.btnRed {
color: red;
}
.btnSoccerBall {
color: white;
position: relative;
margin: auto;
}
.soccer-field {
background-color: lightgreen;
height: 100vh;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
padding: 0 20px; /*optional*/
}
<html lang="en">
<body>
<div class="soccer-field">
<div class="btnBlue">O</div>
<div class="btnSoccerBall">O</div>
<div class="btnRed">O</div>
</div>
</body>
</html>

Cropperjs fixed cropping area height/width to crop image

I'm using cropper.js on MVC 5 Razor page where i do not want user to select cropping area with mouse, I want to initialize cropper object with predefined clipping (selected) area that user can't resize, but user can move clipping area on the picture to crop a part of picture.
I was not able to find any option to disable clipping, i checked on their Git page and it looks like it does not have ability, moreover i posted my request on Git page but did not get any response. i need help how can i workaround to achieve this.
window.onload = function() {
var Cropper = window.Cropper;
var URL = window.URL || window.webkitURL;
var container = document.querySelector('.img-container');
var image = container.getElementsByTagName('img').item(0);
var download = '';
var actions = document.getElementById('actions');
var dataX = 128;
var dataY = 72;
var dataHeight = 1024;
var dataWidth = 576;
var dataRotate = 0;
var dataScaleX = -1;
var dataScaleY = 1;
var options = {
aspectRatio: 16 / 9,
preview: '.img-preview',
ready: function (e) {
console.log(e.type);
},
cropstart: function (e) {
console.log(e.type, e.detail.action);
},
cropmove: function (e) {
console.log(e.type, e.detail.action);
},
cropend: function (e) {
console.log(e.type, e.detail.action);
},
crop: function (e) {
var data = e.detail;
console.log(e.type);
dataX.value = Math.round(data.x);
dataY.value = Math.round(data.y);
dataHeight.value = Math.round(data.height);
dataWidth.value = Math.round(data.width);
dataRotate.value = typeof data.rotate !== 'undefined' ? data.rotate : '';
dataScaleX.value = typeof data.scaleX !== 'undefined' ? data.scaleX : '';
dataScaleY.value = typeof data.scaleY !== 'undefined' ? data.scaleY : '';
},
zoom: function (e) {
console.log(e.type, e.detail.ratio);
}
};
var cropper = new Cropper(image, options);
}
.img-container {
min-height: 497px;
max-width: 497px;
margin-bottom: 1rem;
background-color: white;
text-align: center;
width: 100%;
}
.img-container > img {
max-width: 100%;
}
img {
vertical-align: middle;
border-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.5/cropper.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.5/cropper.css" rel="stylesheet"/>
<div class="img-container">
<img src="https://images.pexels.com/photos/266011/pexels-photo-266011.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260" id="croppr" />
</div>
With reference to help by #Chris W. I was able to setup with fixed clipping area.
var image = document.getElementById('croppr');
var cropper = new Cropper(image, {
dragMode: 'move',
aspectRatio: 16 / 9,
autoCropArea: 0.65,
restore: false,
guides: false,
center: false,
highlight: false,
cropBoxMovable: true,
cropBoxResizable: false,
toggleDragModeOnDblclick: false,
});
.img-container {
min-height: 497px;
max-width: 497px;
margin-bottom: 1rem;
background-color: white;
text-align: center;
width: 100%;
}
.img-container > img {
max-width: 100%;
}
img {
vertical-align: middle;
border-style: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.5/cropper.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.5/cropper.css" rel="stylesheet"/>
<div class="img-container">
<img src="https://images.pexels.com/photos/266011/pexels-photo-266011.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260" id="croppr" />
</div>

How to use the same functions on canvases that have different background images on different pages?

I'm using fabric.js to manipulate different canvases with their own dimensions and background images. My problem is that I'm not sure how to continue using the below functions with new canvases with different background images (I'm stuck with one background image). I've tried creating new canvases with the following for example and controlling their backgrounds with CSS but it breaks the app on the second page:
var canvas = new fabric.Canvas('d');
I'm still learning how to work with different canvases so wasn't sure how to handle this. Thanks in advance.
The Details:
Right now I have 2 pages, one with:
<canvas width="500" height="500" id="c"></canvas>
and the other with:
<canvas width="700" height="700" id="c"></canvas>
They're both using this the following JavaScript and CSS:
var canvas = new fabric.Canvas('c');
// Upload image
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) {
//create shadow
var shadow = {
color: '#888888',
blur: 70,
offsetX: 45,
offsetY: 45,
opacity: 0.8
}
var oImg = img.set({
left: 0,
top: 0,
angle: 0,
stroke: '#fffcf7',
strokeWidth: 20
}).scale(1);
oImg.setShadow(shadow); //set shadow
canvas.add(oImg).renderAll();
var dataURL = canvas.toDataURL({
format: 'png',
quality: 1
});
});
};
reader.readAsDataURL(file);
});
// Add text
function Addtext() {
canvas.add(new fabric.IText('Tap and Type', {
// left: 0,
// top: 0,
fontFamily: 'helvetica neue',
fill: '#000',
stroke: '#000',
strokeWidth: .2,
fontSize: 45
}));
}
// Delete selected object
window.deleteObject = function() {
var activeGroup = canvas.getActiveGroup();
if (activeGroup) {
var activeObjects = activeGroup.getObjects();
for (let i in activeObjects) {
canvas.remove(activeObjects[i]);
}
canvas.discardActiveGroup();
canvas.renderAll();
} else canvas.getActiveObject().remove();
}
// Send selected object to front or back
var selectedObject;
canvas.on('object:selected', function(event) {
selectedObject = event.target;
});
var sendtoback = function() {
canvas.sendToBack(selectedObject);
}
var sendtofront = function() {
canvas.bringToFront(selectedObject);
}
fabric.Object.prototype.set({
transparentCorners: true,
lockUniScaling: true,
cornerColor: '#22A7F0',
borderColor: '#22A7F0',
cornerSize: 12,
padding: 5
});
#c {
background: url(http://i.imgur.com/RkNFWSY.jpg);
}
.myFile {
position: relative;
overflow: hidden;
float: left;
clear: left;
}
.myFile input[type="file"] {
display: block;
position: absolute;
top: 0;
right: 0;
opacity: 0;
font-size: 30px;
filter: alpha(opacity=0);
}
first
Give your canvas (that is on the second page) a different id , for instance d ...
<canvas width="700" height="700" id="d"></canvas>
second
Initiate your new fabric canvas instance as such ...
var id = document.getElementById('c') && c ||
document.getElementById('d') && d;
var canvas = new fabric.Canvas(id);
this will ensure that the appropriate canvas is present on the page
third
Now, set different background image for each canvas (by their id) in your css, like so ...
#c {
background: url(http://i.imgur.com/RkNFWSY.jpg);
}
#d {
background: url(http://i.imgur.com/GYpod56.jpg);
}

Check if my server is responding [Javascript]

I want to check if server at URL is responding, then set the text of my < p > tag to 'server is online' or 'server is offline'.
I can make a page on my server that returns for ex. 'success' as a plain text. And if my javascript can catch this message it should write 'server is online', else it should try to connect for maximum 5 or more seconds, then write a message 'server is offline'.
I tried the code from this answer, but it turns offline after 1500 ms.
<body onload="Pinger_ping('google.com')">
...
<p id = "status">Checking server status...</p>
...
<script type="text/javascript">
function Pinger_ping(ip, callback) {
if(!this.inUse) {
this.inUse = true;
this.callback = callback
this.ip = ip;
var _that = this;
this.img = new Image();
var status=document.getElementById('status');
this.img.onload = function() {status.innerHTML="online";};
this.img.onerror = function() {status.innerHTML="online";};
this.start = new Date().getTime();
this.img.src = "http://" + ip;
this.timer = setTimeout(function() {status.innerHTML="offline";}, 1500);
}
}
</script>
You may try this solution, here I am using image load event to track the connection status.
(function(win) {
var _ = {};
_.win = win;
_.doc = _.win.document;
_.status = _.doc.createElement('div');
_.status.className = "hide";
_.status.innerHTML = "You are now offline !";
_.doc.getElementsByTagName('body')[0].appendChild(_.status);
_.img = new Image();
_.loop = function() {
_.win.setTimeout(_.nextSrc, 5000);
};
_.onLine = function() {
_.status.className = "hide"; // hide
_.loop();
};
_.offLine = function() {
_.status.className = "net-err"; // show
_.loop();
};
_.img.onload = _.onLine;
_.img.onerror = _.offLine;
_.nextSrc = function() {
_.img.src = "https://raw.githubusercontent.com/arvind-web-corner/offline-status/gh-pages/blank.png?" + _.win.Math.random();
};
_.loop();
})(window);
* {
font-family: Calibri, Arial !important;
}
.net-err {
width: 100%;
display: block;
z-index: 999;
padding: 15px 10px;
background: rgb(255, 9, 9);
color: #fff;
font-weight: bold !important;
text-align: center;
position: fixed;
top: -1px;
left: -1px;
border: 1px solid #ddd;
font-size: 30px;
opacity: 0.9;
filter: alpha(opacity=90);
/* IE */
}
.hide {
display: none;
}
<!DOCTYPE html>
<html>
<head>
<title>Status</title>
</head>
<body>
<h1>This page will be tracking your internet connection</h1>
<h2>You will be notified when you loose connection</h2>
<h3>e.g. Go to File > Work Offline</h3>
</body>
</html>
script, demo

Links, Hyperlinks into a canvas using PDF.js

I'm using the PDF.js library to render a pdf into the canvas. That pdf has hyperlinks in there, The PDF.js library is drawing the pdf into the canvas but the hyperlinks don't work.
Any Idea if it possible that hyperlinks work into the canvas?
Thanks
Here is a fiddle that shows you how to enable annotations (including hyperlinks) in PDF files.
The original PDF file used in the fiddle is here.
I used viewer code (web/page_view.js,web/viewer.css) as refrence to write this fiddle.
HTML:
<!doctype html>
<html lang="en">
<head>
<link href="style.css" rel="stylesheet" media="screen" />
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="http://seikichi.github.io/tmp/PDFJS.0.8.715/pdf.min.js" type="text/javascript"></script>
<script src="http://seikichi.github.io/tmp/PDFJS.0.8.715/ui_utils.js"></script>
<script src="./main.js" type="text/javascript"></script>
</head>
<body>
<div id="pdfContainer" class="pdf-content">
<canvas id="the-canvas"></canvas>
<div class="annotationLayer"></div>
</div>
</body>
</html>
CSS:
body {
font-family: arial, verdana, sans-serif;
}
.pdf-content {
border: 1px solid #000000;
}
.annotationLayer > a {
display: block;
position: absolute;
}
.annotationLayer > a:hover {
opacity: 0.2;
background: #ff0;
box-shadow: 0px 2px 10px #ff0;
}
.annotText > div {
z-index: 200;
position: absolute;
padding: 0.6em;
max-width: 20em;
background-color: #FFFF99;
box-shadow: 0px 2px 10px #333;
border-radius: 7px;
}
.annotText > img {
position: absolute;
opacity: 0.6;
}
.annotText > img:hover {
opacity: 1;
}
.annotText > div > h1 {
font-size: 1.2em;
border-bottom: 1px solid #000000;
margin: 0px;
}
JavaScript:
PDFJS.workerSrc = 'http://seikichi.github.io/tmp/PDFJS.0.8.715/pdf.min.worker.js';
$(function () {
var pdfData = loadPDFData();
PDFJS.getDocument(pdfData).then(function (pdf) {
return pdf.getPage(1);
}).then(function (page) {
var scale = 1;
var viewport = page.getViewport(scale);
var $canvas = $('#the-canvas');
var canvas = $canvas.get(0);
var context = canvas.getContext("2d");
canvas.height = viewport.height;
canvas.width = viewport.width;
var $pdfContainer = $("#pdfContainer");
$pdfContainer.css("height", canvas.height + "px")
.css("width", canvas.width + "px");
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
setupAnnotations(page, viewport, canvas, $('.annotationLayer'));
});
function setupAnnotations(page, viewport, canvas, $annotationLayerDiv) {
var canvasOffset = $(canvas).offset();
var promise = page.getAnnotations().then(function (annotationsData) {
viewport = viewport.clone({
dontFlip: true
});
for (var i = 0; i < annotationsData.length; i++) {
var data = annotationsData[i];
var annotation = PDFJS.Annotation.fromData(data);
if (!annotation || !annotation.hasHtml()) {
continue;
}
var element = annotation.getHtmlElement(page.commonObjs);
data = annotation.getData();
var rect = data.rect;
var view = page.view;
rect = PDFJS.Util.normalizeRect([
rect[0],
view[3] - rect[1] + view[1],
rect[2],
view[3] - rect[3] + view[1]]);
element.style.left = (canvasOffset.left + rect[0]) + 'px';
element.style.top = (canvasOffset.top + rect[1]) + 'px';
element.style.position = 'absolute';
var transform = viewport.transform;
var transformStr = 'matrix(' + transform.join(',') + ')';
CustomStyle.setProp('transform', element, transformStr);
var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px';
CustomStyle.setProp('transformOrigin', element, transformOriginStr);
if (data.subtype === 'Link' && !data.url) {
// In this example, I do not handle the `Link` annotations without url.
// If you want to handle those annotations, see `web/page_view.js`.
continue;
}
$annotationLayerDiv.append(element);
}
});
return promise;
}
});
function loadPDFData() {
/*jshint multistr: true */
var base64pdfData = '...'; //should contain base64 representing the PDF
function base64ToUint8Array(base64) {
var raw = atob(base64);
var uint8Array = new Uint8Array(new ArrayBuffer(raw.length));
for (var i = 0, len = raw.length; i < len; ++i) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
return base64ToUint8Array(base64pdfData);
}
Enable Text Selection in PDF.JS
Step 1: Adding a Element to Hold the Text Layer
<div id="text-layer"></div>
This div will be in addition to the element where the PDF is rendered, so the HTML will look like :
<canvas id="pdf-canvas"></canvas>
<div id="text-layer"></div>
Step 2 : Adding CSS for Text Layer
Add the following to your CSS file :
#text-layer {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
opacity: 0.2;
line-height: 1.0;
}
#text-layer > div {
color: transparent;
position: absolute;
white-space: pre;
cursor: text;
transform-origin: 0% 0%;
}
Step 3: Getting the PDF Text
After the PDF has been rendered in the canvas, you need to get the text contents of the PDF, and place that text in the text layer.
// page is the page context of the PDF page
// viewport is the viewport required in renderContext
// For more see https://usefulangle.com/post/20/pdfjs-tutorial-1-preview-pdf-during-upload-wih-next-prev-buttons
page.render(renderContext).then(function() {
// Returns a promise, on resolving it will return text contents of the page
return page.getTextContent();
}).then(function(textContent) {
// PDF canvas
var pdf_canvas = $("#pdf-canvas");
// Canvas offset
var canvas_offset = pdf_canvas.offset();
// Canvas height
var canvas_height = pdf_canvas.get(0).height;
// Canvas width
var canvas_width = pdf_canvas.get(0).width;
// Assign CSS to the text-layer element
$("#text-layer").css({ left: canvas_offset.left + 'px', top: canvas_offset.top + 'px', height: canvas_height + 'px', width: canvas_width + 'px' });
// Pass the data to the method for rendering of text over the pdf canvas.
PDFJS.renderTextLayer({
textContent: textContent,
container: $("#text-layer").get(0),
viewport: viewport,
textDivs: []
});
});
source: https://usefulangle.com/post/90/javascript-pdfjs-enable-text-layer
setupAnnotations = (page, viewport, canvas, annotationLayerDiv) => {
let pdfjsLib = window['pdfjs-dist/build/pdf'];
let pdfjsViewer = window['pdfjs-dist/web/pdf_viewer'];
//BELOW--------- Create Link Service using pdf viewer
let pdfLinkService = new pdfjsViewer.PDFLinkService();
page.getAnnotations().then(function (annotationsData) {
viewport = viewport.clone({
dontFlip: true
});
let pdf_canvas = canvas;
// Render the annotation layer
annotationLayerDiv.style.left = pdf_canvas.offsetLeft + 'px';
annotationLayerDiv.style.top = pdf_canvas.offsetTop + 'px';
annotationLayerDiv.style.height = viewport.height + 'px';
annotationLayerDiv.style.width = viewport.width + 'px';
pdfjsLib.AnnotationLayer.render({
viewport: viewport,
div: annotationLayerDiv,
annotations: annotationsData,
page: page,
linkService: pdfLinkService,
enableScripting: true,
renderInteractiveForms: true
});
}
IMP ---- Do not forget to add this CSS
.annotation-layer{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
opacity: 1;
}
.annotation-layer section{
position: absolute;
cursor: pointer;
}
.annotation-layer section a{
display: block;
width: 100%;
height: 10px;
}
In above example, Link service instance is created using class in pdf viewer, which is being passed as parameter to annotation layer render method.
Please refer source code of PDF.js refer to /web/pdf_viewer.js - class PDFLinkService for more information.
PDF.js version - v2.9.359

Categories