I need to build an object string by string, and then use eval() to create the object.
I was successful doing this with an array of objects, but the next part, an object, is not working.
These three jsFiddles show the progression:
Chart with normal array (pieData) and object (pieOptions)
Chart with array formed of strings - works
Add object formed of strings - no work
There is considerable discussion about why I use eval(). The array and object used for data and options respectively are both formed bit-by-bit as strings, and then glomped together into an array and an object. This jsFiddle will demonstrate a (simpler) version of my problem:
http://jsfiddle.net/81fpdc44/3/
Please show me how to make s1...s5 into an array without using eval(). Am I missing something (not an uncommon situation...) ?
For Posterity: The code
Working (array):
<canvas id="pieChart" height="400" width="300"></canvas>
pieD = '{value:25, color:"red"},';
pieD += '{value:5, color:"blue"},';
pieD += '{value:25, color:"palegreen"},';
pieD += '{value:10, color:"darkcyan"},';
pieD += '{value:35, color:"wheat"}';
eval('pieData = ['+pieD+']');
var pieOptions = {
annotateDisplay : true,
segmentShowStroke : false,
segmentStrokeColor : "white",
segmentStrokeWidth : 1,
percentageInnerCutout : 0,
animation: false,
animationSteps : 100,
animationEasing : "easeOutQuart",
animateRotate : true,
animateScale : false,
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
};
var ctx = document.getElementById("pieChart").getContext("2d");
var myPieChart = new Chart(ctx).Pie(pieData,pieOptions);
Not working:
pieO = 'annotateDisplay : true,';
pieO += 'segmentShowStroke : false,';
pieO += 'segmentStrokeColor : "white",';
pieO += 'segmentStrokeWidth : 1,';
pieO += 'percentageInnerCutout : 0,';
pieO += 'animation: false,';
pieO += 'animationSteps : 100,';
pieO += 'animationEasing : "easeOutQuart",';
pieO += 'animateRotate : true,';
pieO += 'animateScale : false,';
pieO += 'legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"';
eval('pieOptions = {'+pieO+'}');
I have fixed this. The key was understanding that eval() must not ever be used, under any circumstances. (At my present skill level, at least)
Aside from the ajax injection, and JavaScript code being injected with it, here's what I was trying to do. I had these values in variables:
cu = 3;
py = 5;
fs = 7;
qz = 9;
ch = 11;
am = 13;
mi = 15;
mo = 17;
I had to create an array that was part text/part variable (I thought...). So, I tried this:
pDat = ['{value:'+cu+'}, {value:'+py+'}, {value:'+fs+'}, {value:'+qz+'}, {value:'+ch+'}, {value:'+am+'}, {value:'+mi+'}, {value:'+mo+'}'];
That didn't work. So I tried:
eval('pDat = [{value:'+cu+'}, {value:'+py+'}, {value:'+fs+'}, {value:'+qz+'}, {value:'+ch+'}, {value:'+am+'}, {value:'+mi+'}, {value:'+mo+'}']');
That worked for the array, but not for the object.
With the good advice from Vohuman, guest271314, epascarello and other good souls, I went back to the drawing board and refactored the code so that I could just do this:
(And it worked for everything - I was even able to add the variables with the color codes):
pDat = [{value:cu, color:CuCol}, {value:py, color:PyCol}, {value:fs, color:FsCol}, {value:qz, color:QzCol}, {value:ch, color:ChCol}, {value:am, color:AmCol}, {value:mi, color:MiCol}, {value:mo, color:MOCol}];
oOpt = {
annotateDisplay : true,
segmentShowStroke : false,
segmentStrokeColor : "white",
segmentStrokeWidth : 1,
percentageInnerCutout : 0,
animation: false,
animationSteps : 100,
animationEasing : "easeOutQuart",
animateRotate : true,
animateScale : false,
legendTemplate : '<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'
};
var ctx = document.getElementById("pieChart").getContext("2d");
updateChart(ctx,pDat,pOpt,true,false);
Note:
FWIW, CuCol, PyCol etc are just vars that look like this:
CuCol = '#ffe382';
PyCol = '#1bb3a5';
etc
You are using eval for creating an array of objects:
s1 = '{value:25, color:"red"}';
s2 = '{value:5, color:"blue"}';
s3 = '{value:25, color:"palegreen"}';
s4 = '{value:10, color:"darkcyan"}';
s5 = '{value:35, color:"wheat"}';
var pieData = [ s1+s2+s3+s4+s5 ];
The above code snippet is a wrong way of doing this. Here you shouldn't create a string representation of an object (those are not valid JSON strings) when you need a real object. What you should do is:
var s1 = {value:25, color:"red"};
var s2 = {value:5, color:"blue"};
var s3 = {value:25, color:"palegreen"};
var s4 = {value:10, color:"darkcyan"};
var s5 = {value:35, color:"wheat"};
var pieData = [ s1, s2, s3, s4, s5 ];
Now pieData is an array of objects. Done!
Note, adjusted double quotes at <ul> string attributes to single quotes .
Try using String.prototype.split() , Array.prototype.map() , String.prototype.replace() with RegExp /(^[a-zA-Z]+)(?=\s|:)/g to match characters a-z case insensitive followed by space character or colon character ":" property of object string ; JSON.stringify() , JSON.parse()
pieO = 'annotateDisplay : true,';
pieO += 'segmentShowStroke : false,';
pieO += 'segmentStrokeColor : "white",';
pieO += 'segmentStrokeWidth : 1,';
pieO += 'percentageInnerCutout : 0,';
pieO += 'animation: false,';
pieO += 'animationSteps : 100,';
pieO += 'animationEasing : "easeOutQuart",';
pieO += 'animateRotate : true,';
pieO += 'animateScale : false,';
pieO += 'legendTemplate : "<ul class=\'<%=name.toLowerCase()%>-legend\'><% for (var i=0; i<segments.length; i++){%><li><span style=\'background-color:<%=segments[i].fillColor%>\'></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"'
pieO = pieO.split(",").map(function(val, index) {
val = val.replace(/(^[a-zA-Z]+)(?=\s|:)/g, function(match) {
return JSON.stringify(match)
});
return JSON.parse("{" + val + "}")
});
console.log(pieO)
Related
In my projects i need to make my chart more responsive . I print table from chartjs data using too but i got garbage value in table . any other method is also appreciated
var ctxP = canvasP.getContext('2d')
var myPieChart = new Chart(ctxP, {type: 'line',
data:
{
labels: JSON.parse(localStorage.getItem("label")),
datasets: [
{label: "DFT", data: JSON.parse(localStorage.getItem("dft")), borderColor: "ORANGE",fill: false,markerType: "triangle"},
{label: "FUNCTIONAL", data: JSON.parse(localStorage.getItem("fun")), borderColor: "GREEN",fill: false,markerType: "circle"}
]
},
options: {
legend: {
display: true,
position: "right"
}
}
});
addTable(myPieChart);
function addTable(myPieChart){
var tableData = "";
for(var i = 0; i < myPieChart.data.datasets.length; i++)
{
tableData += "<tr>" + "<td style='color:" + myPieChart.data.datasets[i].borderColor +
"'>■" + myPieChart.data.datasets[i].label + "</td>";
for(var j = 0; j < myPieChart.data.datasets[i].data.length; j++){
tableData += ("<td>" + myPieChart.data.datasets[i].data[j].length +"%</td>")
}
tableData += "</tr>";
}
$("#chartData").append(tableData)
}
}</script>
So, what was the error you were getting and what did you expect from the code? Please also provide that, other than that, this code here:
tableData += ("<td>" + myPieChart.data.datasets[i].data[j].length +"%</td>")
is adding the length of the data and not the data itself, remove the .length to get the actual data:
tableData += ("<td>" + myPieChart.data.datasets[i].data[j] +"%</td>")
This is the same addTable() function with a few changes:
function addTable(myPieChart) {
var tableData = "";
var data_size = 0;
for (var i = 0; i < myPieChart.data.datasets.length; i++) {
tableData += "<tr>";
for (var j = 0; j < myPieChart.data.datasets[i].data.length; j++) {
tableData += ("<td>" + myPieChart.data.datasets[i].data[j] + "%</td>")
}
tableData += "<td style='color:" + myPieChart.data.datasets[i].borderColor +
"'>■" + myPieChart.data.datasets[i].label + "</td>";
// Notice how I have swapped the labels with the data
// Because your legend is also on the right
tableData += "</tr>";
}
$("#chartData").append(tableData);
data_size = $('#chartData').children('tr:first').children('td').length;
// Get the size of the data in the table
$('#chartData').children('tr').children('td').css({
// This 500 is the width of the canvas element that holds the chart
// This code makes the width of the cells responsive
width: 500 / data_size
});
}
Also this option makes the chart scale according to your needs:
options: {
//set responsive to false
responsive: false,
legend: {
display: true,
position: "right"
}
}
You can also add this CSS to make it close to what you expect, but this is the closest it can get because they have different structures.
They cannot possibly align perfectly.
#chartData td {
text-align: center;
}
Also try experimenting with more CSS styles and see the outcome
what I am trying to do is append a <select> tag and do an if statement.
I do have error. I think it's the way I am concatenating the string..
here's my code:
var load_volumes = jQuery('.micronic').val();
var arr_volumes = load_volumes.split(',');
var count_volumes = arr_volumes.length;
for(x=0; x<count_volumes; x++){
jQuery('.append_here').append("<select class='volumes'>"
+"<option>Choose Volume</option>"
+"<option"
+ if(arr_volumes[x] == 0.5){
+ "selected"
+ }
+">0.5</option>"
+"<option>0.75</option>"
+"<option>1.10</option>"
+"<option>1.40</option>"
+"<option>2.0</option>"
+"<option>2.5</option>"
+"<option>3.0</option>"
+"<option>4.0</option>"
+"<option>6.0</option>"
+"<option>7.5</option></select>  ");
}
thanks in advance.
See my answer below. You should consider using a template engine such as handlebars though.
jQuery('.append_here').append("<select class='volumes'>"
+"<option>Choose Volume</option>"
+"<option"
+ (arr_volumes[x] == 0.5? " selected" : "")
+">0.5</option>"
+"<option>0.75</option>"
+"<option>1.10</option>"
+"<option>1.40</option>"
+"<option>2.0</option>"
+"<option>2.5</option>"
+"<option>3.0</option>"
+"<option>4.0</option>"
+"<option>6.0</option>"
+"<option>7.5</option></select>  ");
Replace the line with if with ternary selector:
+ (arr_volumes[x] == 0.5? " selected" : "")
The append function should have a single element as an input, but this would produce only warnings. The problem in your code is
+ if(arr_volumes[x] == 0.5){
+ "selected"
+ }
Ideally set this value in advance. Your code could look something like this:
var volumes = (arr_volumes[x] == 0.5) ? " selected" : "";
var select = "<select class='volumes'>"
+"<option>Choose Volume</option>"
+"<option"
+ volumes
+">0.5</option>"
+"<option>0.75</option>"
+"<option>1.10</option>"
+"<option>1.40</option>"
+"<option>2.0</option>"
+"<option>2.5</option>"
+"<option>3.0</option>"
+"<option>4.0</option>"
+"<option>6.0</option>"
+"<option>7.5</option></select>  ";
jQuery('.append_here').append(select);
But consider something like this in the end to make it variable:
var values = [0.5, 0.75, 1.10, 1.40, 2.0, 2.5, 3.0, 4.0, 6.0, 7.5];
var content = "<select class='volumes'>"
for(var i=0; values.length; i++) {
content += "<option";
content += (arr_volumes[x] == values[i]) ? " selected" : "";
content += ">" + values[i] + "</option>";
}
content += "</select>";
Try this way to select
var s="";
if(arr_volumes[x] == 0.5){
s=" selected " ;
}
jQuery('.append_here').append("<select class='volumes'>"
+"<option>Choose Volume</option>"
+"<option"
+ s
+">0.5</option>"
+"<option>0.75</option>"
+"<option>1.10</option>"
+"<option>1.40</option>"
+"<option>2.0</option>"
+"<option>2.5</option>"
+"<option>3.0</option>"
+"<option>4.0</option>"
+"<option>6.0</option>"
+"<option>7.5</option></select>  ");
I'm trying to generate some data with Sage Sdata using javascript and after that handle that data with datatables plugin but I'm getting error:
DataTables warning: table id=example - Requested unknown parameter '1' for row 0. For more information about this error, please see http://datatables.net/tn/4
if(aNode2)
{
resultTextData += '[';
resultTextData += "'" + aNode1.nodeValue + "'";
resultTextData += ',';
resultTextData += "'" + aNode2.nodeValue + "'";
resultTextData += ',';
resultTextData += "'" + aNode3.nodeValue + "'";
resultTextData += ']';
resultTextData += ',';
}
var dataSet = resultTextData ;
console.log(dataSet);
$('#example').dataTable({
"data": dataSet,
"aoColumns": [
{ "aDataSort": [ 0, 1 ] },
{ "aDataSort": [ 1, 0 ] },
{ "aDataSort": [ 2, 3 ] }
]
});
the data option doesn't not accept string inputs. See https://datatables.net/reference/option/data
DataTables support loading from json-encoded string.
Here is Example of converting XML result to array.
function FormatDataByIolist($data,$IOlist) {
$returnAray = array();
$RecordCount = count($data);
for($i = 0; $i < $RecordCount; $i++) {
$tmpSingleRow = array();
foreach($IOlist as $colName) {
$columVal = (string)$data[$i]->$colName;
$tmpSingleRow[$colName] = $columVal;
}
array_push($returnAray,$tmpSingleRow);
unset($tmpSingleRow);
}
return $returnAray;
}
After it you need to convert array to json_encoded string that DataTable can understand.
$formatted = '{ "data": '.json_encode($returnAray).'}';
After writing this in backend you need to add following row in your datatable definition
"ajax": "your.php?action=getJson"
your.php?action=getJson Method should be GET and should return formatted json-string ( as shown ).
I thnik, this repository will help you to work with SData. ( It is model for working with SData )
https://github.com/AramKocharyan/Sage-SData
I am getting out of focus when I am practicing the oop and I don't know how to continue.
I have two code and I need to unite the both code.
I need to initialize the variable of svg by using the method of oop.
Need help.
Thanks.
link svg:
function ArrayMaker(svgcx, svgcy ,svgr ,svgstroke ,svgstroke_width ,svgfill ) {
this.svgcx = 100;
this.svgcy = 50;
this.svgr = 40;
this.svgstroke = "red";
this.svgstroke_width = 3;
this.svgfill = "yellow";
this.theArray = [ this, svgcx ,svgcy ,svgr ,svgstroke ,svgstroke_width ,svgfill ];
}
ArrayMaker.prototype = {
someMethod: function () {
alert( 'someMethod called');
},
getArray: function () {
return this.theArray;
}
};
var am = new ArrayMaker( 'one', 'two' );
var other = new ArrayMaker( 'first', 'second' );
alert(am.getArray());
this code is work:
var cx=100;
var cy=50;
var r=40;
var stroke="red";
var stroke_width=3;
var fill="yellow";
var htm = "<html>";
htm += "<head>";
htm += "<title>test3</title>";
htm += "</head>";
htm += "<body>";
htm += "<svg ";
htm += " version=";
htm += "\"1.1\"";
htm += ">";
htm += "<circle ";
htm += "cx="+cx+" ";
htm += "cy="+cy+" ";
htm += "r="+r+" ";
htm += "stroke="+stroke+" ";
htm += "stroke-width="+stroke_width+" ";
htm += "fill="+fill+" ";
htm += "/>";
htm += "</body>";
htm += "</html>";
document.write(htm);
To create SVG elements with JS you need to use createElementNS() and create elements with the SVG namespace (http://www.w3.org/1999/xhtml). For example, see this demo on my site: http://phrogz.net/SVG/svg_in_xhtml5.xhtml
var svgNS = "http://www.w3.org/1999/xhtml";
function createOn( root, name, attrs ){
var el = document.createElementNS(svgNS,name);
for (var attr in attrs){
if (attrs.hasOwnProperty(attr)) el.setAttribute(attr,attrs[attr]);
}
return root.appendChild(el);
}
var svg = createOn( document.body, 'svg', {viewBox:'-100 -100 200 200'} );
createOn( svg, 'circle', { cx:-60, cy:-50, r:20, fill:'#000' });
Note that SVG attributes are not in any namespace, so you can use setAttribute() (as I did above) or setAttributeNS(null,...). However, this is not true for attributes specified outside of SVG, like XLink's href. For such you need to create the attributes with the correct namespace.
You should move away from w3schools and document.write. They both represent old ways of doing things.
Phrogz answered before me, but I'll post a link to a jsFiddle you can play with anyway.
http://jsfiddle.net/ctrlfrk/nnjsw/
The code in that link will show you how to properly create a 'circle' object, and how to add a method to the prototype (in this case to move the circles)
I have a problem building a HTML table from the following JSON
[
{
"size" : 167,
"price" : 453400,
"type" : "Neubau",
"children" : false
},
{
"size" : 167,
"price" : 453400,
"type" : "Neubau",
"children" : false
},
{
"size" : 167,
"price" : 453400,
"type" : "Neubau",
"children":[
{
"size" : 167,
"price" : 453400,
"type" : "Neubau",
"children" : false
},
{
"size" : 167,
"price" : 453400,
"type" : "Neubau",
"children" : false
}
]
},
{
"size" : 167,
"price" : 453400,
"type" : "Neubau",
"children" : false
}
]
when fed into these functions
function getRowHTML(dataObject, type) {
cycles = dataObject.length;
var markup = '';
for (var i=0; i < cycles; i++) {
// different markup for each line
switch (type) {
case 'size':
markup += ' <td>' + dataObject[i].size + '</td>';
break;
case 'price':
markup += ' <td>' + addDots(dataObject[i].price) + '€ </td>';
break;
case 'type':
markup += ' <td>' + dataObject[i].type + '</td>';
break;
}
// Check if an object has children and insert children HTML as well
if (dataObject[i].children) {
markup += getRowHTML(dataObject[i].children,type);
}
}
return markup;
}
function getHTML(data) {
var markup = '<table>';
markup += '<tr class="odd">' + getRowHTML(data,'size') + '</tr>';
markup += '<tr class="even">' + getRowHTML(data,'price') + '</tr>';
markup += '<tr class="odd">' + getRowHTML(data,'type') + '</tr>';
markup += '</table>';
return markup;
}
Everything works fine until I add the check for children and the corresponding recursive function call.
Then the result are the first two objects and the children but the last one won't be in the table. Any ideas?
You have forgotten the var on the cycles variable, making it an accidental global. The inner call to getRowHTML overwrites the value of the global cycles in the outer call, making the outer loop end early.
Note you also have HTML-injection problems if any of the properties can contain HTML-special characters. You should HTML-escape any content being inserted into an HTML string. Or, to avoid having to think about that, use DOM methods to create the table instead. eg.
function fillRow(row, items, property) {
for (var i= 0, n= items.length; i<n; i++) {
var item= items[i];
var s= item[property];
if (property==='price')
s= addDots(s)+'\u20Ac'; // €
row.insertCell(-1).appendChild(document.createTextNode(s));
if (item.children)
fillRow(row, item.children, property);
}
}
function makeTable(data) {
var table= document.createElement('table');
var properties= ['size', 'price', 'type'];
for (var i= 0, n= properties.length; i<n; i++) {
var row= table.insertRow(-1);
row.className= i%2===0? 'odd' : 'even';
fillRow(row, data, properties[i]);
}
return table;
}