I am using jsPDF-AutoTable plugin for making pdf from HTML table.
But rowspan is not correctly showing please see here the link of jsfiddle.
Here is JS:
function htmlToPdf(autoTableId='', fileName = '', headerHtmlId = '', footerHtmlId='', otherHtmlId = '' ) {
//let doc = new jsPDF();
let doc = new jsPDF('p', 'pt', 'a4', true); //pt = px * .75
let table = autoTableId ? ($("#"+autoTableId).get(0)) : document.getElementById("autoTableId");
let newFileName = fileName ? (fileName + '.pdf') : 'report.pdf';
let headerHtml = headerHtmlId ? ($("#"+headerHtmlId).get(0)) : document.getElementById("headerHtmlId");
let footerHtml = footerHtmlId ? ($("#"+footerHtmlId).get(0)) : document.getElementById("footerHtmlId");
let otherHtml = otherHtmlId ? ($("#"+otherHtmlId).get(0)) : document.getElementById("otherHtmlId");
let startY = 30;
let finalY = doc.previousAutoTable.finalY;
let pageNumber = doc.internal.getNumberOfPages();
doc.setPage(pageNumber);
let totalPagesExp = "{total_pages_count_string}";
// Document default options
doc.autoTableSetDefaults({
//headStyles: {fillColor: [155, 89, 182]}, // Purple, fillColor: 0
//margin: {top: 25},
});
// Document margin list
let margins = {mTop: 10, mBottom: 60, mLeft: 50, pTop: 10, pBottom: 60, pLeft: 50, width: 800};
// Skip elements instead of display: none
let specialElementHandlers = {
'#skipText': function (element,renderer) {
return true;
}
};
// Other content options
let otherContentOptions = {
'width': margins.width, //max width of content on PDF
'elementHandlers': specialElementHandlers,
'pagesplit': true,
};
// Header content options
let header = function(data) {
doc.setFontSize(18);
doc.setTextColor(40);
doc.setFontStyle('normal');
//doc.addImage(headerImgData, 'JPEG', data.settings.margin.left, 20, 50, 50);
/*if (base64Img) {
doc.addImage(base64Img, 'JPEG', data.settings.margin.left, 15, 10, 10);
}*/
//let headerHtml = '<header>Hello Header</header>';
//doc.text(headerHtml, data.settings.margin.left + 15, 22);
doc.fromHTML(
headerHtml,
margins.mLeft, //x coord
margins.mTop, //y coord
otherContentOptions, //options object
margins
);
};
// Footer content options
let footer = function(data) {
let str = "Page " + doc.internal.getNumberOfPages();
// Total page number plugin only available in jspdf v1.0+
if (typeof doc.putTotalPages === 'function') {
str = str + " of " + totalPagesExp;
}
doc.setFontSize(10);
// jsPDF 1.4+ uses getWidth, <1.4 uses .width
let pageSize = doc.internal.pageSize;
let pageHeight = pageSize.height ? pageSize.height : pageSize.getHeight();
doc.text(str, data.settings.margin.left, pageHeight - 10);
};
// Auto table content options
let autoTableOptions = {
html: table,
startY: startY, //false
//margin: {top: 30},
theme: 'plain', //striped, plain, grid
cellWidth: 'auto',
useCss: true,
//tableWidth: 'wrap',
margin: {bottom:20},
tableLineWidth: .75,
tableLineColor: [0, 0, 0],
styles: {
fontSize: 10.5, //14px
font: 'helvetica', //helvetica, times, courier
lineColor: [0, 0, 0], //or single value ie. lineColor: 255,
lineWidth: .75, //1px
cellPadding: 1.5,
textColor: [0, 0, 0],
fillColor: [255, 255, 255], //false for transparent or number or array of number
valign: 'middle', //top, middle, bottom
halign: 'left', //left, center, right
cellWidth: 'auto', //'auto', 'wrap' or a number
overflow: 'ellipsize', //visible, hidden, ellipsize or linebreak
fontStyle: 'normal', //normal, bold, italic, bolditalic
},
// Header & Footer
didDrawPage: function (data) {
// Header Content
header(data);
// Footer Content
footer(data);
},
};
// Auto table content
doc.autoTable(autoTableOptions);
// Total page number
if (typeof doc.putTotalPages === 'function') {
doc.putTotalPages(totalPagesExp);
}
// Output
//doc.save(newFileName);
doc.output("dataurlnewwindow");
}
The above function is to make pdf from HTML table and the HTML is in this jsfiddle
Here is a Screenshot:
Can anyone help me?
If the question is unclear please suggest me and thanks in advance.
Update to the latest version and this should be fixed. If not you can create a new issue in the github repo.
Related
I'm trying to check for a collision between 2 text objects and using the intersectsWithObject. It's working but it's taking the bouding rect into account. Is it possible to check on pixel level?
Current behaviour:
Wanted behaviour:
const canvas = new fabric.Canvas('canvas');
canvas.setWidth(document.body.clientWidth);
canvas.setHeight(document.body.clientHeight);
const text = new fabric.Textbox('some text', {
width: 300,
fontSize: 70,
top: 120,
left: 100
});
const text2 = new fabric.Textbox('some more text', {
width: 350,
fontSize: 50,
top: 200,
left: 20,
})
if (text.intersectsWithObject(text2, true, true)) {
text.set('fill', 'red');
}
else {
text.set('fill', 'black');
}
canvas.on('after:render', function() {
canvas.contextContainer.strokeStyle = '#555';
canvas.forEachObject(function(obj) {
var bound = obj.getBoundingRect();
canvas.contextContainer.strokeRect(
bound.left + 0.5,
bound.top + 0.5,
bound.width,
bound.height
);
})
});
canvas.add(text);
canvas.add(text2);
https://jsbin.com/menadejato/edit?js,console,output
I have a page with two graphics and two tables and I want to put those tables next to each other in a pdf, I'm using jsPDF, but when I put the second table it go right bellow the first one table, how can I put the table bellow??
Here is my code:
let canvas = document.getElementById('chart-s') as HTMLCanvasElement;
let canvas2 = document.getElementById('chart-m') as HTMLCanvasElement;
let canvasImg = canvas.toDataURL("image/jpg", 1.0);
let canvasImg2 = canvas2.toDataURL("image/jpg", 1.0);
let doc = new jsPDF();
doc.setFontSize(20);
doc.text(15, 15, `${moment().format("MMMM")} ${moment().format("YYYY")} - `+"Year");
doc.addImage(canvasImg, 'JPEG', 10, 20, 190, 70 );
doc.addImage(canvasImg2, 'JPEG', 10, 100, 190, 70 );
let tableOne = document.getElementById("table");
let res = doc.autoTableHtmlToJson(tableOne);
doc.autoTable({
head: [[`${moment().subtract(1, "year").format("YYYY")}`, `${moment().format("YYYY")}`]],
body: res.data,
margin: {top: 175, right: 10},
tableWidth: 85
});
let tableTwo = document.getElementById("mtable");
let resd = doc.autoTableHtmlToJson(tableTwo);
doc.autoTable({
head: [[`${moment().subtract(1, "year").format("YYYY")}`, `${moment().format("YYYY")}`]],
body: resd.data,
margin: {right: 50, bottom: 175},
tableWidth: 85
});
doc.save('canvas.pdf');
I'm using chart.js to create diagrams. I might have positive numbers and negative numbers in my data, so I need to fill my diagram from zero point to up, where data is more than 0, and to the bottom where my data is negative. I need to do something like this:
As I found out, property fill: 'origin' must help, but I can't make it to work. This is my fiddle: http://jsfiddle.net/vaxobasilidze/zm470gsq/4/
function factorData(data) {
let _data = data.map((e, i, a) => {
let prev = a[i - 1];
let next = a[i + 1];
if (e === prev && e === next) return '' + e;
return e;
}).map(e => typeof e === 'string' ? null : e);
return _data;
}
var ctx = document.getElementById("chart").getContext("2d");
var gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(250,174,50,1)');
gradient.addColorStop(1, 'rgba(250,174,50,0)');
var gradient1 = ctx.createLinearGradient(0, 0, 0, 400);
gradient1.addColorStop(0, 'rgba(255,0,0,1)');
gradient1.addColorStop(0.5, 'rgba(0,255,0,1)');
gradient1.addColorStop(1, 'rgba(255,0,0,1)');
/***************/
var datas = [];
var labelss = [];
var quantity = 50;
for(var i=0; i<quantity; i++){
var test = Math.floor((Math.random() * 100) - 50);
datas.push(test);
labelss.push("");
}
Chart.types.Line.extend({
name: "LineAlt",
initialize: function () {
Chart.types.Line.prototype.initialize.apply(this, arguments);
var ctx = this.chart.ctx;
var originalStroke = ctx.stroke;
ctx.stroke = function () {
ctx.save();
ctx.shadowBlur = 7;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
originalStroke.apply(this, arguments)
ctx.restore();
}
}
});
var data = {
labels : labelss,
datasets: [
{
fillColor : gradient1, // Put the gradient here as a fill color
strokeColor : gradient1, //"#ff6c23"
pointColor : "#fff",
pointStrokeColor : "rgba(0,0,0,0)",
pointHighlightFill: "#fff",
pointHighlightStroke: "#ff6c23",
data : factorData(datas),
spanGaps: true,
fill: 'origin'
}
]
};
if(quantity > 600){
var options = {
responsive: true,
datasetStrokeWidth : 1,
pointDotRadius: 0,
pointDotStrokeWidth : 0,
pointHitDetectionRadius : 0,
tooltipFillColor: "rgba(120,0,0,0.8)",
tooltipFontStyle: "bold",
bezierCurve: false,
animation: false,
scaleFontColor: "#FFFFFF",
scaleFontStyle: "bold"
};
}
else {
var options = {
responsive: true,
datasetStrokeWidth : 2,
pointDotRadius: 1.5,
pointDotStrokeWidth : 0,
pointHitDetectionRadius : 0,
tooltipFillColor: "rgba(120,0,0,0.8)",
tooltipFontStyle: "bold",
bezierCurve: false,
animation: false,
scaleFontColor: "#FFFFFF",
scaleFontStyle: "bold"
};
}
var myLineChart = new Chart(ctx).LineAlt(data, options);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="chart" width="800" height="400" style="background: #202020"></canvas>
What should I do? I could not find anything similar in the google, is it actually possible using chart.js?
I had the same problem for fill: false.
Version (library) 1 of chartjs has important differences to version 2 in terms of usability. Fine references are: . version 1: https://blog.ruanbekker.com/blog/2017/12/14/graphing-pretty-charts-with-python-flask-and-chartjs/ . version 2: https://towardsdatascience.com/flask-and-chart-js-tutorial-i-d33e05fba845
So I want to save the canvas based on scale 1 and I want to include all existing/visible objects.
So right now, my canvas is 600x400 and if I were to save it, it would only save what's inside that 600x400, and it respects zoom level (a higher zoom will see less things, a lower zoom will see more things but smaller).
I've gotten around this by running this code:
let zoom = this.canvas.getZoom();
this.canvas.setZoom(1);
let url = this.canvas.toDataURL({width: 1000, height: 700, multiplier: 1});
this.canvas.setZoom(zoom);
window.open(
url,
'_blank' // <- This is what makes it open in a new window.
);
What this does is save the image as 1000x700, so stuff that were past 600px but under 1000 still gets saved.
However, this is hard coded. So I was wondering if there was an existing function or a clean/simple way to detect where all the objects are in and returns the full size (width and height).
fiddle: http://jsfiddle.net/1pxceaLj/3/
Update 1:
var gr = new this.fabric.Group([], {
left: 0,
top: 0
});
this.canvas.forEachObject( (o) => {
gr.add(o);
});
this.canvas.add(gr);
this.canvas.renderAll();
console.log(gr.height, gr.width); // 0 0
Solution
Using group was the best idea. Best example: http://jsfiddle.net/softvar/mRA8Z/
function selectAllCanvasObjects(){
var objs = canvas.getObjects().map(function(o) {
return o.set('active', true);
});
var group = new fabric.Group(objs, {
originX: 'center',
originY: 'center'
});
canvas._activeObject = null;
canvas.setActiveGroup(group.setCoords()).renderAll();
console.log(canvas.getActiveGroup().height);
}
One possibility would be to create a kind of Container using a fabricjs group and adding all created objects to this container.
I updated your fiddle here: http://jsfiddle.net/1pxceaLj/4/
Thus, you could just use group.width and group.height, perhaps adding a little offset or minimum values, and there you are having dynamical value to pass into toDataUrl even when having a smaller canvas.
code:
var canvas = new fabric.Canvas('c');
var shadow = {
color: 'rgba(0,0,0,0.6)',
blur: 20,
offsetX: 10,
offsetY: 10,
opacity: 0.6,
fillShadow: true,
strokeShadow: true
}
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: "#FF0000",
stroke: "#000",
width: 100,
height: 100,
strokeWidth: 10,
opacity: .8
});
var rect2 = new fabric.Rect({
left: 800,
top: 100,
fill: "#FF0000",
stroke: "#000",
width: 100,
height: 100,
strokeWidth: 10,
opacity: .8
});
rect.setShadow(shadow);
//canvas.add(rect);
//canvas.add(rect2);
var gr = new fabric.Group([ rect, rect2 ], {
left: 0,
top: 0
});
canvas.add(gr);
function save()
{
alert(gr.width);
alert(gr.height);
let zoom = canvas.getZoom();
var minheight = 700;
canvas.setZoom(1);
let url = this.canvas.toDataURL({width: gr.width, height: gr.height > minheight ? gr.height : minheight, multiplier: 1});
canvas.setZoom(zoom);
window.open(
url,
'_blank'
);
}
I am working with Titanium Appcelerator and I need help in creating Circular progressbar in the app. Can anyone explain me how circular progressbar works and how progress is filled inside circle in circular manner..?
Please use this Alloy Widget now:
https://github.com/manumaticx/circularprogress
Original Answer
I know this is a little late, but I figured this out after about a days work.
I have not tested on android
This is not animated as I did not need it for my needs. To make it animated, look at the second to last line in the function layer3.transform = Ti.UI.create2DMatrix().rotate(angle); You should be able to animate the rotation angle.
var win = Ti.UI.createWindow({
width:'100%',
height:'100%'
});
win.open();
function circularProgressBar(options)
{
var opts = options;
if (opts.percent == null || opts.percent > 1 || opts.percent < 0) opts.percent = 1;
if (opts.size == null) opts.size = 46;
if (opts.margin == null) opts.margin = 4;
if (opts.backgroundColor == null) opts.backgroundColor = '#fff';
if (opts.progressColor == null) opts.progressColor = '#4ba818';
if (opts.topper == null) opts.topper = {};
if (opts.topper.color == null) opts.topper.color = '#fff';
if (opts.topper.size == null) opts.topper.size = 36;
if (opts.font == null) opts.font = {};
if (opts.font.visible == null) opts.font.visible = true;
if (opts.font.size == null) opts.font.size = 12;
if (opts.font.color == null) opts.font.color = '#900';
if (opts.font.shadowColor == null) opts.font.shadowColor = '#aaa';
if (opts.font.shadowRadius == null) opts.font.shadowRadius = 1;
if (opts.font.shadowOffset == null) opts.font.shadowOffset = {};
if (opts.font.shadowOffset.x == null) opts.font.shadowOffset.x = 0;
if (opts.font.shadowOffset.y == null) opts.font.shadowOffset.y = 1;
var mainHolder = Ti.UI.createView({
left: options.left,
right: options.right,
top: options.top,
bottom: options.bottom,
width: opts.size + opts.margin,
height: opts.size + opts.margin,
borderRadius: (opts.size + opts.margin) / 2,
backgroundColor: opts.backgroundColor
});
var holder = Ti.UI.createView({
width: opts.size,
height: opts.size,
borderRadius: opts.size / 2
});
var layer1 = Ti.UI.createView({
width: opts.size,
height: opts.size,
borderRadius: opts.size / 2,
backgroundColor: opts.progressColor
});
var layer2 = Ti.UI.createView({
left: 0,
width: opts.size / 2,
height: opts.size,
anchorPoint: {
x: 1,
y: 0.5
},
backgroundColor: opts.backgroundColor
});
var layer3 = Ti.UI.createView({
right: 0,
width: opts.size / 2,
height: opts.size,
anchorPoint: {
x: 0,
y: 0.5
},
backgroundColor: opts.backgroundColor
});
var layer4 = Ti.UI.createView({
right: 0,
width: opts.size / 2,
height: opts.size,
anchorPoint: {
x: 0,
y: 0.5
},
backgroundColor: opts.progressColor
});
var topper = Ti.UI.createView({
width: opts.topper.size,
height: opts.topper.size,
borderRadius: opts.topper.size / 2,
backgroundColor: opts.topper.color
});
var percentText = Ti.UI.createLabel({
visible: opts.font.visible,
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
color: opts.font.color,
font: {
fontSize:opts.font.size
},
shadowColor: opts.font.shadowColor,
shadowRadius: opts.font.shadowRadius,
shadowOffset: {
x: opts.font.shadowOffset.x,
y: opts.font.shadowOffset.y
},
textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER,
text: (opts.percent * 100) + '%'
});
mainHolder.add(holder);
topper.add(percentText);
holder.add(layer1);
holder.add(layer2);
holder.add(layer3);
holder.add(layer4);
holder.add(topper);
var percent = opts.percent;
var angle = 360 * percent;
layer2.visible = (angle > 180) ? false : true;
layer4.visible = (angle > 180) ? true : false;
layer3.transform = Ti.UI.create2DMatrix().rotate(angle);
return mainHolder;
}
/* Circular Progress Bar Options
percent: A value between 0 and 1
size: The size of the circular progress bar
margin: The margin of the circular progress bar
backgroundColor: The backgroundColor of the circular area
progressColor: The backgroundColor of the progress bar
--
topper.color: The center circle color
topper.size: The size of the center circle
---
font.visible: Boolean to display the font or not
font.color: The font color
font.size: The fontSize
font.shadowColor: The font shadow color
font.shadowRadius: The font shadow radius
font.shadowOffset.x: The x value of the shadow shadowOffset
font.shadowOffset.y: The y value of the shadow shadowOffset
*/
var circleProgress1 = circularProgressBar({
top:50,
percent:0.35,
size:46,
margin:4,
backgroundColor:'#fff',
progressColor:'#4ba818',
topper: {
color:'#fff',
size: 36
},
font: {
visible: true,
color: '#900',
size: 12,
shadowColor: '#aaa',
shadowRadius: 1,
shadowOffset: {
x: 0,
y: 1
}
}
});
win.add(circleProgress1);
All that ^^^ creates this:
edit: The method I used to create this was from Malcom's idea from this thread: https://developer.appcelerator.com/question/154274/is-there-a-way-to-create-circular-progress-bar
This isn't a progress bar at all - its an "Activity Indicator".
It doesn't show true progress like a progress bar. With a progress bar, you can set a value for your progress (0-100%, for example). This will just "spin" to let users know that they need to wait.
To create an activity indicator, see here: http://docs.appcelerator.com/titanium/2.0/#!/api/Titanium.UI.ActivityIndicator
Quick example:
var activityView = Ti.UI.createView({visible: false});
var activityIndicator = Ti.UI.createActivityIndicator({
message: 'Loading...',
height:'auto',
width:'auto'
});
activityView.add(activityIndicator);
activityView.show();
This example will work, but its not styled. I'll leave it up to you to decide how you want it to look. Tho if you want it to look anything like the image you posted, look at backgroundColor, borderRadius, and transparency on the view property.