PHP: d3.js script does not display anything - php

Problem: I've got the following code, that runs fine as a standalone .html file. Now, I wish to display this within a .php file. Inside the .php file, I've copy-pasted the same code.
There are some header/footer and other html in the main page where this .php file is to be displayed. However, when I run it But other than the line, "Testing", the chart does not display.
What additional changes should be done ?
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<div>
<h4>Testing</h4>
</div>
<!-- <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.4.5"></script> -->
<script src="d3.v3.js"></script>
<!-- Source for example located at: http://bl.ocks.org/1203641 -->
<style type="text/css">
.slice text {
font-size: 16pt;
font-family: Arial;
}
</style>
<script>
var canvasWidth = 500, //width
canvasHeight = 700, //height
outerRadius = 200, //radius
color = d3.scale.category20(); //builtin range of colors
var dataSet = [
{"legendLabel":"Your child's Percentile", "magnitude":90},
{"legendLabel":"Ahead of your child", "magnitude":10},
// {"legendLabel":"Three", "magnitude":50},
// {"legendLabel":"Four", "magnitude":16},
// {"legendLabel":"Five", "magnitude":50},
// {"legendLabel":"Six", "magnitude":8},
// {"legendLabel":"Seven", "magnitude":30}
];
var vis = d3.select("body")
.append("svg:svg") //create the SVG element inside the <body>
.data([dataSet]) //associate our data with the document
.attr("width", canvasWidth) //set the width of the canvas
.attr("height", canvasHeight) //set the height of the canvas
.append("svg:g") //make a group to hold our pie chart
.attr("transform", "translate(" + 1.5*outerRadius + "," + 1.5*outerRadius + ")") // relocate center of pie to 'outerRadius,outerRadius'
// This will create <path> elements for us using arc data...
var arc = d3.svg.arc()
.outerRadius(outerRadius);
var pie = d3.layout.pie() //this will create arc data for us given a list of values
.value(function(d) { return d.magnitude; }) // Binding each value to the pie
.sort( function(d) { return null; } );
// Select all <g> elements with class slice (there aren't any yet)
var arcs = vis.selectAll("g.slice")
// Associate the generated pie data (an array of arcs, each having startAngle,
// endAngle and value properties)
.data(pie)
// This will create <g> elements for every "extra" data element that should be associated
// with a selection. The result is creating a <g> for every object in the data array
.enter()
// Create a group to hold each slice (we will have a <path> and a <text>
// element associated with each slice)
.append("svg:g")
.attr("class", "slice"); //allow us to style things in the slices (like text)
arcs.append("svg:path")
//set the color for each slice to be chosen from the color function defined above
.attr("fill", function(d, i) { return color(i); } )
//this creates the actual SVG path using the associated data (pie) with the arc drawing function
.attr("d", arc);
// Add a legendLabel to each arc slice...
arcs.append("svg:text")
.attr("transform", function(d) { //set the label's origin to the center of the arc
//we have to make sure to set these before calling arc.centroid
d.outerRadius = outerRadius + 50; // Set Outer Coordinate
d.innerRadius = outerRadius + 45; // Set Inner Coordinate
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle") //center the text on it's origin
.style("fill", "Purple")
.style("font", "bold 12px Arial")
.text(function(d, i) { return dataSet[i].legendLabel; }); //get the label from our original data array
// Add a magnitude value to the larger arcs, translated to the arc centroid and rotated.
arcs.filter(function(d) { return d.endAngle - d.startAngle > .2; }).append("svg:text")
.attr("dy", ".35em")
.attr("text-anchor", "middle")
//.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")"; })
.attr("transform", function(d) { //set the label's origin to the center of the arc
//we have to make sure to set these before calling arc.centroid
d.outerRadius = outerRadius; // Set Outer Coordinate
d.innerRadius = outerRadius/2; // Set Inner Coordinate
return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")";
})
.style("fill", "White")
.style("font", "bold 12px Arial")
.text(function(d) { return d.data.magnitude; });
// Computes the angle of an arc, converting from radians to degrees.
function angle(d) {
var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
return a > 90 ? a - 180 : a;
}
</script>
</meta>
</head>
</html>

Works fine for me. The only difference is that I replaced your script tags with remote ones
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v2.1.0.min.js"></script>
If you are including this file from another PHP file, delete doctype, html, body and head tags - they can't be duplicate in generated file.
update: by the way, div tags don't belong to head section

Related

Loop random background image

I want to show a random background image, that starts a loop of random other background images after five seconds.
First I create an array for my background-images:
<?php
$bg = array('bg1.jpg', 'bg2.jpg', 'bg3.jpg', 'bg4.jpg', 'bg5.jpg', 'bg6.jpg', 'bg7.jpg', 'bg8.jpg', 'bg9.jpg', 'bg10.jpg', 'bg11.jpg');
$i = rand(0, count($bg)-1);
$selectedBg = "$bg[$i]";
?>
Second I append a random image to my body:
<style>
#media screen and (min-width: 600px) {
body {
background-image: url(<?php bloginfo('template_url'); ?>/images/backgrounds/<?php echo $selectedBg; ?>);
}
}
</style>
Now I would like to use php or jQuery to select another random image and change the background. How can I achieve this?
If you want to loop your background image every 5 seconds (without having the user reloading the page), you can't do it on PHP, it must be done client side (Javascript).
PHP is a tool to generate the HTML code that will be rendered on the user's browser, but it can't change the page afterward, which is what javascript is made for.
<script type="text/javascript">
// declare list of backgrounds
var images = ['bg-01.jpg', 'bg-02.jpg', 'bg-03.jpg', 'bg-04.jpg', 'bg-05.jpg', 'bg-06.jpg', 'bg-07.jpg'];
// declare function that changes the background
function setRandomBackground() {
// choose random background
var randomBackground = images[Math.floor(Math.random() * images.length)];
// set background with jQuery
$('body').css('background-image', 'url("images/' + randomBackground + '")');
}
// declare function that sets the initial background, and starts the loop.
function startLoop() {
// Set initial background.
setRandomBackground();
// Tell browser to execute the setRandomBackground every 5 seconds.
setInterval(setRandomBackground, 5 * 1000);
}
// One the page has finished loading, execute the startLoop function
$(document).ready(startLoop);
</script>
try using less and js like:
var timeout = 1000;
var action = function() {
var random = Math.floor(Math.random() * 6) + 1 ;
if(random.length<=1){random = '0'+random;}
var wynikLos = 'path/to/file/bg-'+random+'.jpg';
less.modifyVars({
'#img': wynikLos
});
setTimeout(action, timeout);
};
action();
In Less:
body{background-image:#img;}
http://lesscss.org/
p.s.
not tested

Canvas and PHP - Drawing connected line segments

I am trying to draw connected lines using canvas from data in a MySql table. The table (gene_dna_segments) contains the length of each line segment and the segment name.
The desired output is a continuous straight horizontal line comprised of each of the segments. Each segment also needs to have the segment name showing above the corresponding segment as shown in the image below:
+----------------------+--------------------+------------------+--------------------+
| gene_dna_segments_pk | gene_expression_fk | dna_segment_name | dna_segment_length |
+----------------------+--------------------+------------------+--------------------+
| 1 | 11 | Exon 1 | 50 |
| 2 | 11 | Intron 1 | 75 |
| 3 | 11 | Exon 2 | 20 |
| 4 | 11 | Intron 2 | 90 |
+----------------------+--------------------+------------------+--------------------+
Query (old fashioned no PDO...):
$query_dna = "SELECT * FROM gene_dna_segments WHERE gene_expression_fk = '11'";
$result_dna = mysql_query($query_dna, $connection) or die(mysql_error());
Display:
<canvas id="canvas" width="800" height="500"></canvas>
<script type="text/javascript">
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
<?php
while($row_dna = mysql_fetch_assoc($result_dna)) {
echo "context.beginPath();context.moveTo(100, 100);context.lineTo(" . $row_dna['dna_segment_length'] . ", 100);context.lineWidth = 12;context.strokeStyle = '#009543';context.stroke();context.font = 'bold 12pt Calibri';
context.fillStyle = '#009543';
context.fillText('" . $row_dna['dna_segment_name'] . "', 180, 90);";
}
?>
</script>
Now, the line segments and text as defined in the table are drawn OK, but on top of each other as the context.moveTo(100, 100) is the same for each row that is output in the while loop. How should this be handled so that the segments are drawn as a continuous line?
Possibly the easiest thing is to add a start point column to the table and calculate the start points for each segment based on the previous segment's length...I've opened a seperate question on that possibility Calculating new array values based on another numeric array
Note that 'normal' code to draw the lines is like the following code, note that the moveto parts start at the end of the previous line. I need to do the same in the loop...
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(100, 100);
context.lineTo(150, 100);
context.lineWidth = 12;
context.strokeStyle = '#009543';
context.stroke();
context.font = 'bold 11pt Calibri';
context.fillStyle = '#009543';
context.fillText('Exon 1', 105, 90);
context.beginPath();
context.moveTo(150, 100);
context.lineTo(225, 100);
context.lineWidth = 12;
context.strokeStyle = '#e97300';
context.stroke();
context.font = 'bold 11pt Calibri';
context.fillStyle = '#e97300';
context.fillText('Intron 1', 165, 90);
context.beginPath();
context.moveTo(225, 100);
context.lineTo(275, 100);
context.lineWidth = 12;
context.strokeStyle = '#009543';
context.stroke();
context.font = 'bold 11pt Calibri';
context.fillStyle = '#009543';
context.fillText('Exon 2', 230, 90);
context.beginPath();
context.moveTo(275, 100);
context.lineTo(375, 100);
context.lineWidth = 12;
context.strokeStyle = '#e97300';
context.stroke();
context.font = 'bold 11pt Calibri';
context.fillStyle = '#e97300';
context.fillText('Intron 2', 300, 90);
[ Updated based on new info from questioner ]
What you're describing is a horizontally stacked bar-chart
Demo: http://jsfiddle.net/m1erickson/RzMWS/
Your barchart is fairly straightforward.
Small problem:
We need to display the segment_name label above each bar. In a perfect world, we could use the segment_length for the bar width. But in reality, sometimes the resulting bar width will be too narrow to fit the text label above.
Therefore, we must preprocess the data and determine an appropriate scale factor for the bars. By scaling the bars proportionally, each bar will remain proportional to their segment_length and will also be wide enough to fit the segment_name label.
Here is heavily commented code.
Of course, you will read from your database fetch instead of reading the test data in the rows[] array.
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
// get references to the canvas
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.font = 'bold 11pt Calibri';
// define the color of the bar for each segment_name
var colorCodes={
Exon1:"green",
Intron1:"orange",
Exon2:"green",
Intron2:"orange"
};
// create some test data
var rows=[];
rows.push({dna_segment_name:"Exon 1",dna_segment_length:50});
rows.push({dna_segment_name:"Intron 1",dna_segment_length:75});
rows.push({dna_segment_name:"Exon 2",dna_segment_length:20});
rows.push({dna_segment_name:"Intron 2",dna_segment_length:90});
// some variables
// segments[]: pre-processed data will be saved into segments[]
// scaleFactor: scales every bar if any text label fails to fit
// padding: allow minimum padding between text labels
var segments=[];
var scaleFactor=1;
var padding=5;
// pre-process
// Of course, you will be reading from your database Fetch
// instead of this test data in rows[]
for(var i=0;i<rows.length;i++){
var $row_dna=rows[i];
// make variables for the segment_name & segment_length
// being read from the data fetch
var name=$row_dna['dna_segment_name'];
var length=$row_dna['dna_segment_length'];
// lookup the color for this segment_name
var color=colorCodes[name.replace(/\s+/g, '')];
// rescale the bars if any text won't fit
var textWidth=ctx.measureText(name).width+padding;
var textRatio=textWidth/length;
if (textRatio>scaleFactor){ scaleFactor=textRatio; }
// save the pre-processed info in a javascript object
// for later processing
segments.push({
name:name,
length:length*scaleFactor,
color:color
});
}
// draw the stacked bar-chart
// based on the preprocessed JS objects in segments[]
var accumLength=0;
var y=100; // the Y-coordinate of the barchart
for(var i=0;i<segments.length;i++){
// load the object for the current bar
var segment=segments[i];
// set the bar color
ctx.fillStyle=segment.color;
// draw the bar
ctx.fillRect(accumLength,y,segment.length,12);
// draw the text label
ctx.fillText(segment.name,accumLength,y-10);
// accumulate where the next bar will begin
accumLength+=segment.length;
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=400 height=300></canvas>
</body>
</html>

Filling D3.js Pie Graph with SQL Query

I am currently using D3.js to make a pie graph. The data is stored in a MSSQL database, which is then converted to JSON using PHP. Here is my code that does that
<?php
// Server Name
$myServer = "SRVR";
// Database
$myDB = "TestDB";
// If using Windows Authentication, get rid of, "'UID'=>$myUser, 'PWD'=>$myPass, "
// Notice that the latest driver uses sqlsrv rather than mssql
$conn = sqlsrv_connect('Database'=>$myDB));
// Change TestDB.vwTestData to YOURDB.dbo.YOURTABLENAME
$sql = "SELECT col, SUM(num) AS 'value'
FROM db
GROUP BY col";
$result = array();
do {
while ($row = sqlsrv_fetch_array($data, SQLSRV_FETCH_ASSOC)){
$result[] = $row;
}
} while ( sqlsrv_next_result($data) );
// This will output in JSON format if you try to hit the page in a browser
echo json_encode($result);
sqlsrv_free_stmt($data);
sqlsrv_close($conn);
?>
This works fine. I've tested it, and it outputs JSON in something like this:
[{"col":null,"value":247.9042254},{"col":"value1","value":16.8151576061},{"col":"value2","value":235.4833175609},{"col":"value3","value":2316.072432028},{"col":"value4","value":8904.4001532729}]
How can I put this in the graph? Here is my .js code
(function() {
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return // Something goes here I assume });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.json("scripts/graphs/script.php", function(error, data) {
data.forEach(function(d) {
// Something needs to go here?
});
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.age); });
g.append("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.data.age; });
});
})();
If someone could help me out, that would be great. Thanks!
I figured it out. I used this code and customized it for JSON
https://gist.github.com/enjalot/1203641
Here is what I got
(function() {
var w = 670, //width
h = 326, //height
r = 150, //radius
color = d3.scale.category20c(); //builtin range of colors
d3.json("script.php", function (data) {
var vis = d3.select("body")
.append("svg:svg") //create the SVG element inside the <body>
.data([data]) //associate our data with the document
.attr("width", w) //set the width and height of our visualization (these will be attributes of the <svg> tag
.attr("height", h)
.append("svg:g") //make a group to hold our pie chart
.attr("transform", "translate(" + r + "," + r + ")") //move the center of the pie chart from 0, 0 to radius, radius
var arc = d3.svg.arc() //this will create <path> elements for us using arc data
.outerRadius(r);
var pie = d3.layout.pie() //this will create arc data for us given a list of values
.value(function(d) { return d.value; }); //we must tell it out to access the value of each element in our data array
var arcs = vis.selectAll("g.slice") //this selects all <g> elements with class slice (there aren't any yet)
.data(pie) //associate the generated pie data (an array of arcs, each having startAngle, endAngle and value properties)
.enter() //this will create <g> elements for every "extra" data element that should be associated with a selection. The result is creating a <g> for every object in the data array
.append("svg:g") //create a group to hold each slice (we will have a <path> and a <text> element associated with each slice)
.attr("class", "slice"); //allow us to style things in the slices (like text)
arcs.append("svg:path")
.attr("fill", function(d, i) { return color(i); } ) //set the color for each slice to be chosen from the color function defined above
.attr("d", arc); //this creates the actual SVG path using the associated data (pie) with the arc drawing function
arcs.append("svg:text") //add a label to each slice
.attr("transform", function(d) { //set the label's origin to the center of the arc
//we have to make sure to set these before calling arc.centroid
d.innerRadius = 0;
d.outerRadius = r;
return "translate(" + arc.centroid(d) + ")"; //this gives us a pair of coordinates like [50, 50]
})
.attr("text-anchor", "middle") //center the text on it's origin
.text(function(d, i) { return data[i].col; }); //get the label from our original data array
})
})();
So what was wrong was that I wasn't connecting the key values from the JSON, to the variables in the JS. Here are the lines to change:
var vis = d3.select("<PUT DIV ID HERE>")
.value(function(d) { return d.<PUT NUMBER VALUE KEY NAME HERE>; });
.text(function(d, i) { return data[i].<PUT SLICE CATEGORY HERE>; });
I am not entirely certain what is not working about your code, but you could try something simple like:
d3.json("scripts/graphs/script.php", function(error, data) {
data.forEach(function(d) {
d.value = +d.value
});
var g...
Alternately, could you just call the php script and store the returned json object in a variable, then pass that variable to d3.json?

Change image size on click of button in jQuery

I am working on image upload and I need to add functionality for image shapes.
There are buttons for landscape, portrait, square and panoramic. When the user clicks any of these, the div shape will change accordingly.
This is the code for the square shape but when I click on the square shape, it stretches the image. I want to change the shape of the div without stretching the image.
$('#Square').on('click', function(){
var images = $("#uploadedImage");
for(i=0; i<images.length; i++)
images[i].onload = centerImage(images[i]);
function centerImage(img) {
if (img.width > img.height ) {
var y = 160;
var x = img.width/img.height*y;
var marx = (x-y)/2;
img.style.height = y+"px";
img.style.marginLeft = -(marx) + "px";
}
}
});
It's difficult to recreate running example without more generalized code, but your function clearly changes the dimensions of variable img, the image passed in to the function, and not any div or other element besides the image that was clicked. If you want to change a div based on the same HxW test of the image, change the img.* parts of your function to $('#DivYouWant').* and you should get on the right track. Something along the lines of:
function centerImage(img) {
if (img.width > img.height ) {
var y = 160;
var x = img.width/img.height*y;
var marx = (x-y)/2;
$('#DivYouWannaMod').height = y+"px";
$('#DivYouWannaMod').marginLeft = -(marx) + "px";
}
}

<div> of images, retrieved by getJSON, disappear after append()

I'm working on a GMaps application to retrieve images, via getJSON(), and to populate a popup marker.
The following is the markup which I add to the marker dynamically:
<div id="images"></div>
<div id="CampWindow" style="display:none;width:550px;height:500px;">
<h4 id="camp-title"></h4>
<p>View... (all links open in new windows)</p>
<ul>
<li><a id="camp-hp-link" target="_blank" href="">camp home page</a></li>
<li>information: <a id="camp-av-link" target="_blank" href="">availability</a> | <a id="camp-vi-link" target="_blank" href="">vital information</li>
</ul>
<p id="message"></p>
I've been clawing out my eyes and woohoo for the past couple of days, trying to get the images to show inside the CampWindow . Then, I decided to think laterally and to see if the images were being retrieved at all. I then moved the images outside and sure as Bob (Hope), the images were being retrieved and refreshed with every click.
So, I decided to the keep the images outside and then once loaded, append it to the CampWindow . It's not working still; when I append the div to the main CampWindow div, the images won't show. I check in Firebug with the pointer thingy and it shows me the images as empty. I try it again with the images outside and it shows the images. I've tried before append and appendTo with no success. Am I missing something here?
I have no more woohoo to claw out. Please, please help.
marker.clicked = function(marker){
$("#images").html('');
$('#camp-title').text(this.name);
$('#camp-hp-link').attr('href', this.url);
$('#camp-av-link').attr('href', this.url + '/tourism/availability.php');
$('#camp-vi-link').attr('href', this.url + '/tourism/general.php');
// get resort images via jQuery AJAX call - includes/GetResortImages.inc.php
$.getJSON('./includes/GetResortImages.inc.php', { park: this.park_name, camp: this.camp_name }, RetrieveImages);
function RetrieveImages (data)
{
if ('failed' == data.status)
{
$('#messages').append("<em>We don't have any images for this rest camp right now!</em>");
}
else
{
if ('' != data.camp)
{
$.each(data, function(key,value){
$("<img/>").attr("src", value).appendTo('#images');
});
}
}
}
//.append($("#images"));
$("#CampWindow").show();
var windowContent = $("<html />");
$("#CampWindow").appendTo(windowContent);
var infoWindowAnchor = marker.getIcon().infoWindowAnchor;
var iconAnchor = marker.getIcon().iconAnchor;
var offset = new google.maps.Size(infoWindowAnchor.x-iconAnchor.x,infoWindowAnchor.y-iconAnchor.y);
map.openInfoWindowHtml(marker.getLatLng(), windowContent.html(), {pixelOffset:offset});
}
markers.push(marker);
});
When you add the <html> tag to your page it confuses the browser and is most likely the problem. I would suggest to either do as Pointy said and use window.open() to make a popup window (check out this tutorial), or better yet try out one of the many jQuery light box plugins.
I'm not sure what you are doing with the google maps, so I decided to just go with a basic example for you. With this script, if you click on an image inside the #image div, it'll open a popup window the same size as the image.
$(document).ready(function(){
$('#images img').click(function(){
var padding = 20;
var w = $(this).width() + padding;
var h = $(this).height() + padding;
var popup = '\
<html>\
<head>\
<link type="text/css" href="popup-style.css" rel="stylesheet" />\
<scr'+'ipt type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></scr'+'ipt>\
</head>\
<body>\
<img src="' + $(this).attr('src') + '">\
</body>\
</html>';
var pop = window.open('','Image View','toolbar=0,location=0,status=0,width=' + w + ',height=' + h + ',scrollbars=1,resizable=1');
pop.document.write(popup);
pop.document.close();
})
});
NOTE: When adding a script tag inside a string, make sure you break up the word "script" otherwise you will get an error.
Update #2:
Ok, since you want to work with what you have, try doing this:
Remove the <html> tag from your campwindow, then position your campwindow using CSS and/or javascript. Add something like:
var w = $(window).width();
var h = $(window).height();
// Add overlay and make clickable to hide popup
// you can remove the background color and opacity if you want to make it invisible
var $overlay = $('<div/>', {
'id': 'overlay',
css: {
position : 'absolute',
height : h + 'px',
width : w + 'px',
left : 0,
top : 0,
background : '#000',
opacity : 0.5,
zIndex : 99
}
}).appendTo('body');
// Position your popup window in the viewport
$('#CampWindow').css({
position: 'absolute',
top : $(window).scrollTop() + 50 + 'px',
left : w/2 - $('#CampWindow').width()/2 + 'px', // centers the popup
zIndex : 100
})
.fadeIn('slow');
// Click overlay to hide popup
$('#overlay').click(function(){
$('#CampWindow').hide();
$(this).remove(); // remove the overlay
})

Categories