Image is chopped while generating PDF from PieCharts (Amchart) - javascript

I want to export my pie chart as pdf , everything is fine when results are limited to 5-6, after that image is chopping in PDF See the image below
Chopped Image in PDF
The Problem I am getting is because we are using Scrollbar if result is large See the image below
Generating Pie Charts.Due to this scroll bar we are not able to capture the image of the report hence we are getting the chopped image. Can anyone help me with this issue. Below is the code we are using for generating pdf from piecharts
// Collect actual chart objects out of the AmCharts.charts array
var ids = ["chartdiv-" +data.id];
var charts = {}
var charts_remaining = ids.length;
for (var i = 0; i < ids.length; i++) {
for (var x = 0; x < AmCharts.charts.length; x++) {
if(!(charts[ids[i]])){
if (AmCharts.charts[x].div.id == ids[i])
if(this.criteria.fullView && AmCharts.charts[x].container.height > 290 && AmCharts.charts[x].container.height != 330 && document.body.contains(AmCharts.charts[x].containerDiv))
charts[ids[i]] = AmCharts.charts[x];
else if(AmCharts.charts[x].container.height == 330 && this.criteria.dashBoard && document.body.contains(AmCharts.charts[x].containerDiv))
charts[ids[i]] = AmCharts.charts[x];
else if(!this.criteria.fullView && !this.criteria.dashBoard && AmCharts.charts[x].container.height > 290 && document.body.contains(AmCharts.charts[x].containerDiv))
charts[ids[i]] = AmCharts.charts[x];
}
}
}
// Trigger export of each chart
for (var x in charts) {
if (charts.hasOwnProperty(x)) {
var chart = charts[x];
chart.export.capture({}, function() {
this.toJPG({ multiplier: 2 }, function(data) {
// Save chart data into chart object itself
this.setup.chart.exportedImage = data;
// Reduce the remaining counter
charts_remaining--;
// Check if we got all of the charts
if (charts_remaining == 0) {
// Yup, we got all of them
// Let's proceed to putting PDF together
generatePDF();
}
});
});
}
}
function generatePDF() {
var id = divId;
var layout = {
"content": []
}
layout.content.push(
{"text": name, "fontSize": 13, "fit": [ 523.28, 769.89 ]},
{
"image": charts["chartdiv-"+id].exportedImage,
"width" : 40,
"fit": fitParam
}, { "text": content, "fontSize": 10});
chart["export"].toPDF(layout, function(data) {
this.download(data, "application/pdf", "amCharts.pdf");
});
}
};

Related

Javascript in Photoshop: changing text content increases font size

I am using a Javascript function (found on this site) to change the content of a text layer:
var doc = app.activeDocument;
changeTextLayerContent(doc, "LAYER1", "new text");
function changeTextLayerContent(doc, layerName, newTextString) {
for (var i = 0, max = doc.layers.length; i < max; i++) {
var layerRef = doc.layers[i];
if (layerRef.typename === "ArtLayer") {
if (layerRef.name === layerName && layerRef.kind === LayerKind.TEXT) {
layerRef.textItem.contents = newTextString;
}
} else {
changeTextLayerContent(layerRef, layerName, newTextString);
}
}
}
This does change the text correctly. But it has a side effect of doubling the font size each time it is run.
Can anyone explain why please?
Thanks,
Antony

Canvas.js slows down

The problem:
The problem I am encountering is that for each "JQuery event" click, the canvas.js diagram slows down proporsjonal to the click? I believe $(document).ready(function(){ is responsible.
That is to say 10 clicks slows down the applciation 10 times. Keep in mind that I have five canvas.js diagrams (tables). Canvas.js
Table1.js (The same code structure goes for the other diagrams, table2,table3 etc).
(function table1(){
$(document).ready(function(){
var dps = []; // data
var chart = new CanvasJS.Chart("table1",
{
title:{
text: "Exhaust Temperature"
data: [
{
type: "spline",
name: "Temp Cylinder 1",
showInLegend: "true",
legendText: "Temp Cylinder 1",
dataPoints: dps1
}
});
var xVal = 0;
var updateInterval = 50;
var dataLength = 50;
var updateChart = function (count) {
count = count || 1;
// count is number of times loop runs to generate random dataPoints.
for (var j = 0; j < count; j++) {
dps.push({
x: xVal,
y: EXTS[1]
});
xVal++;
};
if (dps.length > dataLength )
{
dps.shift();
}
chart.render();
};
// generates first set of dataPoints
updateChart(dataLength);
// update chart after specified time.
setInterval(function(){updateChart()}, updateInterval);
});
}());
This is JQuery event that is responsible for showing and hiding the diagrams, keep in mind that the user can only view one diagram at time.
$('[data-row]').on('click', function() {
var row = $(this).attr('data-row');
$('.active').removeClass('active');
$('#table' + row).addClass('active');
if (row == 1){
$.getScript("table1.js", function(){});
table1();
} else if (row == 2) {
$.getScript("table2.js", function(){});
table2();
} else if (row == 3) {
$.getScript("table3.js", function(){});
table3();
}
});

Multi-item responsive carousel

I'm building a website that requires a carousel to be implemented. Because this website is built on AngularJS I wanted to go with Angulars Boostrap Carousel, however, this carousel appears to only allow one image at a time.
What I will need will be 3 images at a time on desktop, on a tablet 2 images and on mobile 1. So there's a significant element of responsive design involved here too.
Does anyone have any experince with this that doesn't involve JQuery? I'm not opposed to it but have been told by a senior member of the team to try to source an alternative, if any.
What I tried from Angulars bootstrap:
$scope.getPromoURLs = function() {
var subObj = myJSON.response.details.promotionalSpots;
for( var keys in subObj ) {
var value = subObj[keys].promotionUrl;
$scope.slides.push( value );
}
};
// Builts an array of promotional URLS to from a JSON object to source the images
$scope.getPromoURLs();
$scope.addSlide = function () {
// Test to determine if 3 images can be pulled together - FAILS
var newWidth = 600 + slides.length;
slides.push({
image: ''+slides[0]+''+slides[1] // etc
// Tried to stitch images together here
});
};
// TODO Should examine array length not hardcoded 4
for (var i = 0; i < 4; i++) {
$scope.addSlide();
}
ui-bootstrap's carousel is not a good choice, it has other drawback like isolated scope on each slide.
I'm using https://github.com/revolunet/angular-carousel which support multi item on each slide.
Because this directive support ng-repeat. You easy change you collection and using nested ng-repeat to set different number of items in each slide.
<ul rn-carousel class="image">
<li ng-repeat="images in imageCollection">
<div ng-repeat="image in images" class="layer">{{ image }}</div>
</li>
</ul>
As you have already defined 3 break points. We just need to reconstruct the imageCollection array when viewport size changed.
$window.on('resize', function() {
var width = $window.width();
if(width > 900) {
// desktop
rebuildSlide(3);
} else if(width <= 900 && width > 480) {
// tablet
rebuildSlide(2);
} else {
// phone
rebuildSlide(1);
}
// don't forget manually trigger $digest()
$scope.$digest();
});
function rebuildSlide(n) {
var imageCollection = [],
slide = [],
index;
// values is your actual data collection.
for(index = 0; index < values.length; index++) {
if(slide.length === n) {
imageCollection.push(slide);
slide = [];
}
slide.push(values[index]);
}
imageCollection.push(slide);
$scope.imageCollection = imageCollection;
}
So, I tried this one so as to make angularjs Carousel (ui.bootstrap.carousel) to work with multi items per animation. I have also tried to apply [Detection for Responsive Websites using AngularJS].2
Take a look here: http://plnkr.co/edit/QhBQpG2nCAnfsb9mpTvj?p=preview
Results:
1 ) One Item (Mobile Version) :
2 ) Two Items (Tablet Version) :
3 ) Three Items (Desktop Version) :
PART 2:
It can also detect the resolution of the window so as to determine if it is tablet,mobile or desktop following this tutorial...
Try to use this values: "mobile, tablet, desktop" to see the three different view versions.
Demonstration of the tablet version:
var app = angular.module('myApp', ['ui.bootstrap', 'angular-responsive']);
app.controller('MainCtrl', function($scope) {
$scope.displayMode = 'mobile'; // default value
$scope.$watch('displayMode', function(value) {
switch (value) {
case 'mobile':
// do stuff for mobile mode
console.log(value);
break;
case 'tablet':
// do stuff for tablet mode
console.log(value);
break;
}
});
});
function CarouselDemoCtrl($scope) {
var whatDevice = $scope.nowDevice;
$scope.myInterval = 7000;
$scope.slides = [{
image: 'http://placekitten.com/221/200',
text: 'Kitten.'
}, {
image: 'http://placekitten.com/241/200',
text: 'Kitty!'
}, {
image: 'http://placekitten.com/223/200',
text: 'Cat.'
}, {
image: 'http://placekitten.com/224/200',
text: 'Feline!'
}, {
image: 'http://placekitten.com/225/200',
text: 'Cat.'
}, {
image: 'http://placekitten.com/226/200',
text: 'Feline!'
}, {
image: 'http://placekitten.com/227/200',
text: 'Cat.'
}, {
image: 'http://placekitten.com/228/200',
text: 'Feline!'
}, {
image: 'http://placekitten.com/229/200',
text: 'Cat.'
}, {
image: 'http://placekitten.com/230/200',
text: 'Feline!'
}];
var i, first = [],
second, third;
var many = 1;
//##################################################
//Need to be changed to update the carousel since the resolution changed
$scope.displayMode = "tablet";
//##################################################
if ($scope.displayMode == "mobile") {many = 1;}
else if ($scope.displayMode == "tablet") {many = 2;}
else {many = 3;}
for (i = 0; i < $scope.slides.length; i += many) {
second = {
image1: $scope.slides[i]
};
if (many == 1) {}
if ($scope.slides[i + 1] && (many == 2 || many == 3)) {
second.image2 = $scope.slides[i + 1];
}
if ($scope.slides[i + (many - 1)] && many == 3) {
second.image3 = $scope.slides[i + 2];
}
first.push(second);
}
$scope.groupedSlides = first;
}
app.directive('dnDisplayMode', function($window) {
return {
restrict: 'A',
scope: {
dnDisplayMode: '='
},
template: '<span class="mobile"></span><span class="tablet"></span><span class="tablet-landscape"></span><span class="desktop"></span>',
link: function(scope, elem, attrs) {
var markers = elem.find('span');
function isVisible(element) {
return element && element.style.display != 'none' && element.offsetWidth && element.offsetHeight;
}
function update() {
angular.forEach(markers, function(element) {
if (isVisible(element)) {
scope.dnDisplayMode = element.className;
return false;
}
});
}
var t;
angular.element($window).bind('resize', function() {
clearTimeout(t);
t = setTimeout(function() {
update();
scope.$apply();
}, 300);
});
update();
}
};
});
Hope it helps!

Chart.js data structure, how can I dynamically fill this with an array and random colors?

I'm using chart.js to display a Doughnut chart on my site, I'd like to be able to populate the values in the chart dynamically with an array of content pulled from somewhere else on the page. Chart.js stores it's values for the Doughnut chart in this data structure
var doughnutData = [
{
value: 10,
color:"#F7464A"
},
{
value : 10,
color : "#46BFBD"
},
{
value : 20,
color : "#FDB45C"
},
{
value : 50,
color : "#949FB1"
}
];
How can I populate the values of this data structure dynamically in Javascript?
I already know how I'm going to generate the random colors using this (for anyone interested)
'#'+Math.floor(Math.random()*16777215).toString(16)
The issue you're going to have is that actual randomness isn't really perceived as random, so you're going to have to figure out a way to check the color similarity between each of these colors to make sure they don't appear to be indistinguishable. I've done this before with three colors (below). What I would suggest instead is creating a list of colors that you already know are dissimilar and randomly choosing from that list instead.
I tried to keep my colors within a certain range:
function getRandomColor() {
var color = '';
 while (!color.match(/(#[c-e].)([e-f][a-f])([9-c].)/)) {
color = '#' + Math.floor(Math.random() * (Math.pow(16,6))).toString(16);
}
return color;
}
function getColorSimilarityIndex(c1, c2) {
var index = 0;
for (i = 1; i <= 6; i++) {
if (i == 1 || i == 5) {
if (c1.substring(i, i + 1) === c2.substring(i, i + 1)) {
index++;
}
}
}
return index;
}
var color1 = getRandomColor();
var color2 = getRandomColor();
var color3 = getRandomColor();
while (getColorSimilarityIndex(color2, color1) > 0) {
color2 = getRandomColor();
}
while (getColorSimilarityIndex(color3, color1) > 0 || getColorSimilarityIndex(color3, color2) > 0) {
color3 = getRandomColor();
}
You have to build the array with the appropriate elements in it like the below:
var getcolor = function (num) {
if (num == 0)
return "#F38630";
if (num == 1)
return "#E0E4CC";
if (num == 2)
return "#69D2E7";
if (num == 3)
return "#003399";
if (num == 4)
return "#969696";
};
var piedata = []
for (i = 0; i <= self.countViolationsByManager().length - 1; i++) {
piedata.push({
value: self.countViolationsByManager()[i].Count(),
label: self.countViolationsByManager()[i].MoneyManagerName(),
color: getcolor(i)
});
}
var pieoptions = {
}
var ctx = $("#myPieChart").get(0).getContext("2d");
var myNewChart = new Chart(ctx);
new Chart(ctx).Pie(piedata, pieoptions);

JQuery FLOT chart dynamic Y-axis

I have a flot chart that calculates the max Y-axis value based on the last 100 data points and then plots successfully...
BUT
Sometimes, the running total of an ongoing plot (5 second delay with new data point plotted) exceeds the current max limit.
Is there a way to have the Y-axis scale dynamically while plotting new points on the chart?
This is a valid question about how to dynamically scale the Y Axis of the chart if the current Y-axis is exceeded, since the chart is plotted over time with new points being added every 5 seconds, I was asking how to scale the Y-Axis to fit the NEW plot data if it reaches above the current Max Y Axis value..
UPDATE:
here is the code I use (Json returned data) as well as the plot update timer:
The "highY" takes the last 100 datapoints from a database and sets the max value to the highest count + 10%
<script type="text/javascript">
$(function () {
var str1 = [], totalPoints = 300;
var str2 = [], totalPoints = 300;
var pts1 = '';
var pts2 = '';
if (pts1 == "" || pts == null) { pts = '2012-10-02 17:17:02'; }
if (pts2 == "" || pts == null) { pts = '2012-10-02 17:17:02'; }
var maxYaxis = <?PHP echo $highY; ?>;
function getStr1() {
var ts1 = new Date().getTime();
var json1 = (function () {
var json1 = null;
var myURL = '<?PHP echo $updateURL; ?>?s=1&ts=' + ts1;
$.ajax({
'async': false,
'global': false,
'url': myURL,
'dataType': "json",
'success': function (data) {
json1 = data;
}
});
return json1;
})();
var y1 = json1['data']['avgpersec'];
var total_1 = json1['data']['running_total'];
document.getElementById('<?PHP echo $string1; ?>Total').innerHTML = total_1;
if (str1.length > 0) { str1 = str1.slice(1); }
while (str1.length < totalPoints) {
var prev = str1.length > 0 ? str1[str1.length - 1] : 50;
str1.push(y1);
}
// zip the generated y values with the x values
var res = [];
for (var i = 0; i < str1.length; ++i){ res.push([i, str1[i]]) }
return res;
}
function getStr2() {
var ts2 = new Date().getTime();
var json2 = (function () {
var json2 = null;
var myURL = '<?PHP echo $updateURL; ?>?s=2&ts=' + ts2;
$.ajax({
'async': false,
'global': false,
'url': myURL,
'dataType': "json",
'success': function (data) {
json2 = data;
}
});
return json2;
})();
var y2 = json2['data']['avgpersec'];
var total_2 = json2['data']['running_total'];
document.getElementById('<?PHP echo $string2; ?>Total').innerHTML = total_2;
if (str2.length > 0) { str2 = str2.slice(1); }
while (str2.length < totalPoints) {
var prev = str2.length > 0 ? str2[str2.length - 1] : 50;
str2.push(y2);
}
// zip the generated y values with the x values
var res = [];
for (var i = 0; i < str2.length; ++i){ res.push([i, str2[i]]) }
return res;
}
// setup control widget
var updateInterval = 5000;
$("#updateInterval").val(updateInterval).change(function () {
var v = $(this).val();
if (v && !isNaN(+v)) {
updateInterval = +v;
if (updateInterval < 1)
updateInterval = 1;
if (updateInterval > 2000)
updateInterval = 2000;
$(this).val("" + updateInterval);
}
});
// setup plot
var options = {
series: { shadowSize: 0 }, // drawing is faster without shadows
yaxis: { min: 0, max: maxYaxis},
xaxis: { show: false },
colors: ["<?PHP echo $string1Color; ?>","<?PHP echo $string2Color; ?>"]
};
var plot = $.plot($("#placeholder"), [ getStr1(), getStr2() ], options);
function update() {
plot.setData([ getStr1(), getStr2() ]);
plot.draw();
setTimeout(update, updateInterval);
}
update();
});
</script>
What i am hoping to accomplish is to adjust the "$highY" (Y-axis) value real time as i plot new data points so that the chart will scale if the value of the new data plot point exceeds the current "yaxis { max: # }" set in the chart options.
I'm assuming that right now you're using flot.setData and flot.draw?
The simplest solution is just to call $.plot with the new data each time you receive it. At various times, this has been recommended by the authors of the flot plugin as a reasonably efficient way of dealing with this situation. I've used this on graphs that refresh every second and found that it does not use an excessive amount of CPU on the user's computer, even with 3-4 graphs refreshing every second on one page.
EDIT based on the code you added (and your suggested edit), I would change the update function to look like this:
function update() {
var data = [ getStr1(), getStr2() ];
//modify options to set the y max to the new y max
options.yaxis.max = maxYaxis;
$.plot($("#placeholder"), data, options);
setTimeout(update, updateInterval);
}
Additionally, you would add code to getStr and getStr that keep the maxYaxis variable up to date.

Categories

Resources