In the canvas i am using clipTo function to crop it.It works for circle,rectangle,....i could add whatever like text and images after that.I added the code below which works.
$(function(){
var canvas = new fabric.Canvas('Canvas',{backgroundColor: '#ffffff',preserveObjectStacking: true});
canvas.clipTo = function (ctx) {
ctx.arc(250, 300, 200, 0, Math.PI*2, true);
};
canvas.add(new fabric.IText('Welcome ', {
left : fabric.util.getRandomInt(120,120),
top:fabric.util.getRandomInt(400, 400)
}));
canvas.renderAll();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.18/fabric.js"></script>
<div class="container">
<div id='canvascontain' width='1140' height='600' style='left:0px;background-color:rgb(240,240,240)'>
<canvas id="Canvas" width='1140' height='600'></canvas>
</div>
After that i am trying to crop the canvas by SVG file.This also works.But problem is i could not add texts or images after clipTo by canvas.The below code is not adding the text to canvas.
fabric.loadSVGFromURL('https://s3-us-west-2.amazonaws.com/fabric-canvas/test.svg', function (objects, options) {
var shape = fabric.util.groupSVGElements(objects, options);
canvas.clipTo = function (ctx) {
shape.render(ctx);
};
canvas.renderAll();
});
canvastext = new fabric.IText('Hi to all',{
left : fabric.util.getRandomInt(120, 120),
top:fabric.util.getRandomInt(400, 400)
});
canvas.add(canvastext);
canvas.renderAll();
The canvas image is:
Thanks in advance.
I have found the solution.Instead of using loadSVGFromURL i am fetching the path from svg file and cropped the canvas like below.
HTML:
<div id='svgpath'>
<object data="test.svg" type="image/svg+xml"
id="svgpathd" width="100%" height="100%"></object>
</div>
Script:
canvas.clipTo = function (ctx) {
var a = document.getElementById("svgpathd");
a.addEventListener("load",function(){
var svgDoc = a.contentDocument;
var clippath = svgDoc.getElementsByTagName("clipPath")[0].getAttribute('id');
var path = svgDoc.getElementsByTagName("path");
for(i=0;i<path.length;i++){
if(svgDoc.getElementsByTagName("path")[i].getAttribute('clip-path')=="url(#"+clippath+")"){
pathd = svgDoc.getElementsByTagName("path")[i].getAttribute('d');
paths = pathd.replace(" L"," L");
localStorage.setItem('svgpathd', paths);
}
}
});
}
document.getElementById('svgpath').style.display='none';
svgpathd = localStorage.getItem('svgpathd');
//Path has been taken and clipping the canvas with the path values
ctx.beginPath();
var path = svgpathd.split("L");
var arr = [];
m = path[0].slice(1).split(" ");
ctx.moveTo(m[0],m[1]);
for(i=0;i<path.length;i++){
arr[i]=path[i].slice(0,-1).slice(1);
}
for(i=0;i<arr.length;i++){
p = arr[i].split(" ");
ctx.lineTo(p[0],p[1]);
}
ctx.fill();
ctx.closePath();
}
Related
I'm trying to convert a wordtree Google visualization to an image. The current code below runs the wordtree so I can see the visual, but I can't figure out the last section to convert to an image or export as an image. (var my_div = section to end)
I have tried changing code from link below, but can't get it to save as an image.
https://developers.google.com/chart/interactive/docs/printing
I'm also doing this inside of jsfiddle.net to try and make this work.
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current'); // Don't need to specify chart libraries!
google.charts.setOnLoadCallback(drawVisualization);
function drawVisualization() {
google.visualization.drawChart({
"containerId": "mywordtree",
"dataSourceUrl": "https://docs.google.com/spreadsheets/d/1vi-YzV7s7eZ25938Q57DbZvT0iqggiCqRvDgxeZtP6c/edit?usp=sharing",
"query":"SELECT A",
"chartType": "WordTree",
"options": {
wordtree: {
format: 'implicit',
//alt type is 'suffix', 'prefix'
type: 'suffix',
word: 'prescription'
}
}
});
}
var my_div = document.getElementById('chart_div');
var my_chart = new google.visualization.ChartType(mywordtree);
google.visualization.events.addListener(my_chart, 'ready', function () {
mywordtree.innerHTML = '<img src="' + my_chart.getImageURI() + '">';
});
my_chart.draw(data);
</script>
</head>
<body style="font-family: Arial;border: 0 none;">
<div id="mywordtree" style="width: 1000px; height: 1000px;"></div>
</body>
</html>
first, in order to generate an image of the chart,
you need to wait for the chart's 'ready' event.
in order to wait for the 'ready' event,
you need access to the chart object.
you will not be able to use the google.visualization.drawChart method,
because it does not return a handle to the chart.
next, the WordTree chart, does not have a method for getImageURI,
so you will need to create the image manually, from a blob.
see following working snippet...
google.charts.load('current').then(function () {
// get chart container
var container = document.getElementById('mywordtree');
// create chart
var chart = new google.visualization.ChartWrapper({
chartType: 'WordTree',
containerId: container.id,
dataSourceUrl: 'https://docs.google.com/spreadsheets/d/1vi-YzV7s7eZ25938Q57DbZvT0iqggiCqRvDgxeZtP6c/edit?usp=sharing',
options: {
wordtree: {
format: 'implicit',
//alt type is 'suffix', 'prefix'
type: 'suffix',
word: 'prescription'
}
}
});
// listen for ready event
google.visualization.events.addListener(chart, 'ready', function () {
var domUrl; // object url
var image; // chart image
var imageUrl; // chart image url
var svg; // svg element
// add svg namespace to chart
svg = container.getElementsByTagName('svg')[0];
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
// create image url from svg
domUrl = window.URL || window.webkitURL || window;
imageUrl = domUrl.createObjectURL(new Blob([svg.outerHTML], {type: 'image/svg+xml'}));
// create chart image
image = new Image();
image.onload = function() {
// replace chart with image
container.innerHTML = image.outerHTML;
}
image.src = imageUrl;
});
// draw chart
chart.draw();
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="mywordtree"></div>
Setup
I have a simple setup like so:
<video src="/myvideo.mp4" id="my-vid" preload></video>
<script>
var chunks = [];
var vid = document.getElementById("my-vid");
vid.onloadeddata = function() {
var mr = new MediaRecorder(vid.captureStream(), {
mimeType: "video/webm; codecs=opus,vp8"
});
mr.ondataavailable = function(e) {
chunks.push(e.data);
}
mr.start();
vid.play();
vid.muted = false;
}
// ----
// everything below here just downloads the file so I can
// run it though ffprobe
// ----
vid.onended = function() {
setTimeout(function(){
var blob = new Blob(chunks, {type: "video/webm; codecs=opus,vp8"});
var link = document.createElement("a");
document.body.appendChild(link);
link.style = "display: none;";
var url = URL.createObjectURL(blob);
link.href = url;
link.download = "content.webm";
link.click();
URL.revokeObjectURL(url);
document.body.removeChild(link);
}, 1000);
}
</script>
My video is 640 pixels by 360 pixels in size.
What I want
What I want is to scale the output video so that it blows it up to 1920 by 1080 (yes, I realize it will be blocky and ugly -- that's okay. I just need the resolution to match a second video so the two can be stitched together more easily)
What I've tried
Simply changing the <video> tag has no effect:
<video src="/myvideo.mp4" id="my-vid" preload height="1080" width="1920"></video>
This changes the display size, but not the decoded size (and therefore the MediaRecorder still returns a 640x360 video)
I can scale the video by using a <canvas> element like so:
<script>
// ...
vid.onplay = function() {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
(function loop() {
ctx.drawImage(vid, 0, 0, vid.videoWidth, vid.videoHeight, 0, 0, 1920, 1080);
setTimeout(loop, 1000 / 30); // 30 fps
})();
}
</script>
If I then use mr = new MediaRecorder(canvas) instead of mr = new MediaRecorder(vid) then I get a scaled video, but there's no audio!
There is an example given at http://www.rgraph.net/blog/2013/january/an-example-of-html5-canvas-drag-n-drop.html
I am not able to add multiple images into canvas 1 and move those added images to canvas 2. Also I should be able to drag(move the added image within canvas 2) those added images in second canvas.
function dragDrop(e, ui) {
// get the drop point (be sure to adjust for border)
var x = parseInt(ui.offset.left - offsetX) - 1;
var y = parseInt(ui.offset.top - offsetY);
// get the drop payload (here the payload is the $tools index)
var theIndex = ui.draggable.data("toolsIndex");
// drawImage at the drop point using the dropped image
ctx.drawImage($tools[theIndex], x, y, 32, 32);
}
http://jsfiddle.net/cyur7/
This jsfiddle link is working fine.
This solution uses the KineticJS library to accomplish your need.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/bSpBF/
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.1.min.js"></script>
<style>
body{ background-color: ivory; padding:10px;}
#container1,#container2{
border:solid 1px #ccc;
margin-top: 10px;
width:300px;
height:100px;
}
#container2{
height:300px;
}
</style>
<script>
$(function(){
var highlightWidth=8;
var stage = new Kinetic.Stage({
container: 'container1',
width: 300,
height: 100
});
var layer = new Kinetic.Layer();
stage.add(layer);
var dropzone = new Kinetic.Stage({
container: 'container2',
width: 300,
height: 300
});
var dropLayer = new Kinetic.Layer();
dropzone.add(dropLayer);
// these must go after the creation of stages & layers
addBackground(stage,layer,dropLayer);
layer.draw();
addBackground(dropzone,dropLayer,layer);
dropLayer.draw();
// get images & then trigger start()
var images={};
var URLs = {
house1: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg',
house2: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-4.jpg',
house3: 'https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg'
};
loadImages(URLs,start);
function start(){
var house1=kImage(images.house1,10,10,50,50,layer);
var house2=kImage(images.house2,75,10,50,50,layer);
var house3=kImage(images.house3,140,10,50,50,layer);
layer.draw();
}
function swapStagesIfSelected(sourceLayer,destinationLayer,startX,startY){
// get all elements on the source layer
var elements=sourceLayer.get("Image");
// don't let dropped elements fall off the stage
var totalWidth=0;
var maxHeight=-999;
var layerWidth=destinationLayer.getStage().getWidth();
var layerHeight=destinationLayer.getStage().getHeight();
for(var i=0;i<elements.length;i++){
if(elements[i].isSelected){
totalWidth+=elements[i].getWidth();
maxHeight=Math.max(elements[i].getHeight(),maxHeight);
}
}
if(startX+totalWidth>layerWidth){
startX=layerWidth-totalWidth-15;
}
if(startY+maxHeight>layerHeight){
startY=layerHeight-maxHeight-15;
}
// move all selected images
// to the clicked x/y of the destination layer
for(var i=0;i<elements.length;i++){
var element=elements[i];
if(element.isSelected){
var img=element.getImage();
kImage(img,startX,startY,element.getWidth(),element.getHeight(),destinationLayer);
startX+=element.getWidth()+10;
element.remove();
}
}
sourceLayer.draw();
destinationLayer.draw();
}
// build the specified KineticJS Image and add it to the specified layer
function kImage(image,x,y,width,height,theLayer){
var image=new Kinetic.Image({
image:image,
x:x,
y:y,
width:width,
height:height,
strokeWidth:0.1,
stroke:"green",
draggable:true
});
image.myLayer=theLayer;
image.isSelected=false;
image.on("click",function(){
highlight(this);
this.myLayer.draw();
});
image.myLayer.add(image);
return(image);
}
// build a background image and add it to the specified stage
function addBackground(theStage,theLayer,otherLayer){
var background = new Kinetic.Rect({
x: 0,
y: 0,
width: theStage.getWidth(),
height: theStage.getHeight(),
fill: "white",
stroke: "green",
strokeWidth: 1
});
background.on("click",function(){
var pos=theStage.getMousePosition();
var mouseX=parseInt(pos.x);
var mouseY=parseInt(pos.y);
swapStagesIfSelected(otherLayer,theLayer,mouseX,mouseY);
});
theLayer.add(background);
}
///////////// Image loader
function loadImages(URLs, callback) {
var loaded = 0;
var needed = 0;
for(var url in URLs) { needed++; console.log(url); }
for(var url in URLs) {
images[url] = new Image();
images[url].onload = function() {
if(++loaded >= needed) {
callback(images);
}
};
images[url].src = URLs[url];
}
}
///////////// Toggle Highlighting
function highlight(element,setStrokeWidth){
if(setStrokeWidth){
element.setStrokeWidth(setStrokeWidth);
}else{
if(element.getStrokeWidth()>5){
element.setStrokeWidth(0.1);
element.isSelected=false;
}else{
element.setStrokeWidth(highlightWidth);
element.isSelected=true;
}
}
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Click on image(s) to toggle selection</p>
<p>Then click in the other canvas to drop</p>
<div id="container1"></div>
<div id="container2"></div>
<button id="clear">Clear Hightlights</button>
<button id="swap">Swap Selected</button>
</body>
</html>
I have a canvas element on my page. I draw an image over it and some data that the user entered. On a press of a button I want to send the canvas to printer, to print it on paper. I tried to use this plug-in: jQuery.printElement, like that:
the button code:
PRINT
'print_voucher()' function:
function print_voucher()
{
$("#canvas_voucher").printElement();
}
canvas_voucher is the ID of my canvas element. It printed the page, but didn't print the canvas. I tried to use it like that as well:
$("#canvas_voucher img").printElement();
But that didn't even start the printer.
So how can I do that? How can I print the content of the canvas?
**EDIT**
Here's the code that creates my canvas and tries to create an image with it:
function create_voucher(visitor_name, visitor_identity_num, unique_number)
{
var canvas = $("#canvas_voucher")[0];
if (canvas.getContext)
{
var ctx = canvas.getContext('2d');
// Draw image
var img = new Image();
img.src = 'https://someurl.com/image.jpg';
img.onload = function(){
ctx.drawImage(img,0,0);
ctx.fillStyle="#CCC";
ctx.font="bold 20px Arial";
ctx.fillText(visitor_name, 750, 270);
ctx.fillText(visitor_identity_num, 750, 295);
ctx.font="bold 25px Arial";
ctx.fillText(unique_number, 620, 325);
}
var voucher = canvas.toDataURL("image/png");
$("#voucher_img").attr("src", voucher);
} else {
alert('You need Safari or Firefox 1.5+ to see this.');
}
}
This will convert the canvas to a .png image URL and open it in a new browser window
The Print Dialog is triggered to let the user print the page.
function print_voucher(){
var win=window.open();
win.document.write("<br><img src='"+canvas.toDataURL()+"'/>");
win.print();
win.location.reload();
}
Here is example code:
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.fillStyle="gold";
ctx.strokeStyle="blue";
ctx.lineWidth=5;
ctx.rect(50,50,100,100);
ctx.fill();
ctx.stroke();
function print_voucher(){
var win=window.open();
win.document.write("<br><img src='"+canvas.toDataURL()+"'/>");
win.print();
win.location.reload();
}
$("#printVoucher").click(function(){ print_voucher(); });
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas><br>
<button id="printVoucher">Print</button>
</body>
</html>
Found the problem and fixed it.
Apparently it was a security issue at this line:
img.src = 'https://someurl.com/image.jpg';
Once it was pointing out to a server, it was considered as a potential security threat. So I changed it to:
img.src = 'images/image.jpg';
After that I created a function to make an image from the canvas and called it within the 'img.onload' part:
...
img.onload = function(){
ctx.drawImage(img,0,0);
ctx.fillStyle="#CCC";
ctx.font="bold 20px Arial";
ctx.fillText(visitor_name, 750, 270);
ctx.fillText(visitor_identity_num, 750, 295);
ctx.font="bold 25px Arial";
ctx.fillText(unique_number, 620, 325);
draw_voucher_img();
...
function draw_voucher_img()
{
var canvas = $("#canvas_voucher")[0];
var voucher = canvas.toDataURL();
$("#voucher_img").attr("src", voucher);
}
Now it worked!
I want to save the objects of the canvas and put them to JSON, but when I do it with a Group, I get the following error:
o.setCoords is not a function in all.js (Zeile 10403), while executing _calcBound() Function on the Rect-Object.
Here my test code:
<script type="text/javascript">
$(document).ready(function() {
var canvas = new fabric.Canvas("pitch_600");
var group = new fabric.Group();
var rect = new fabric.Rect({
width: 100,
height: 200,
left: 10,
top: 50,
fill: 'black'
});
group.add(rect);
canvas.add(group);
var saved = JSON.stringify(canvas.toDatalessJSON());
canvas.clear();
console.debug(saved);
canvas.loadFromJSON(saved);
});
</script>
<canvas id="pitch_600" width="650px" height="454px"></canvas>
On http://tacticboards.xaga.de/test.html You can find a online demo of it.
I hope you can help.