Seahorsepip Veteran Posted October 22, 2014 Veteran Share Posted October 22, 2014 I was looking for a simple way of making a line graph with svg. Since I did not really want to include yet another library for something that seemed quite simple I decided to write something myself. After some fiddling around I came up with the following php file which returns a svg graph based on the url parameter values you pass to it: <?php header('Content-type: image/svg+xml'); echo '<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'; if(isset($_GET[0])) { $points = $_GET; } else { echo "<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"></svg>"; die(); } $height = max($points); $step = 100/(count($points)-1); $path = $line = "m-10,".($height+10)." l0,-".($points[0]+10)." l10,0 "; for($p=1;$p<count($points);$p++) { $path .= "l$step,".($points[$p-1]-$points[$p])." "; } $path .= "l10,".($points[count($points)-1]+10)." z"; ?> <svg width="100%" height="100%" id="graph" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 <?php echo $height;?>" preserveAspectRatio="none"> <linearGradient id="linearGradient" x1="0" y1="0" x2="0" y2="100%"> <stop style="stop-color:#5677fc;stop-opacity:.3;" offset="0" /> <stop style="stop-color:#5677fc;stop-opacity:0;" offset="1" /> </linearGradient> <path id="line" stroke-width="2px" vector-effect="non-scaling-stroke" style="fill:url(#linearGradient);stroke:#5677fc;" d="<?php echo $path;?>" /> </svg> As example I use it like this: <?php $points = array(100,28,89,33,54,12,90,56,84,37,19,129); ?> <img class="graph" src="/img/graph.php?<?php echo http_build_query($points);?>" /> What do you guys think? Is this a bad or a good idea? Anything to improve? I'm thinking about making it possible to add multiple lines. Oh and here's a image of the graph : Depicus and +Zlip792 2 Share Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted October 22, 2014 Author Veteran Share Posted October 22, 2014 here's updated code for multiple graphs: usage: <?php $a = array(45,28,89,33,54,12,90,56,84,37,19,129); $b = array(66,100,65,0,30,57,3,53,71,20,23,47); //count($a) and count($b) must be equal $colors = array("5677fc","fbc157"); $points = array("points"=>array($a,$b),"colors"=>$colors); ?> <img class="graph" src="graph.php?<?php echo http_build_query($points);?>" /> graph.php: <?php header('Content-type: image/svg+xml'); echo '<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'; if(isset($_GET["points"])) { $values = $_GET["points"]; $colors = $_GET["colors"]; } else { echo "<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"></svg>"; die(); } $paths = array(); $mergevalues = array(); foreach($values as $points) { $mergevalues = array_merge($mergevalues,$points); } $height = max($mergevalues); foreach($values as $i => $points) { $step = 100/(count($points)-1); $paths[$i] = $line = "m-10,".($height+10)." l0,-".($points[0]+10)." l10,0 "; for($p=1;$p<count($points);$p++) { $paths[$i] .= "l$step,".($points[$p-1]-$points[$p])." "; } $paths[$i] .= "l10,".($points[count($points)-1]+10)." z"; } ?> <svg width="100%" height="100%" id="graph" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 <?php echo $height;?>" preserveAspectRatio="none"> <?php foreach($colors as $color) { echo ' <linearGradient id="gradient'.$color.'" x1="0" y1="0" x2="0" y2="100%"> <stop style="stop-color:#'.$color.';stop-opacity:.3;" offset="0" /> <stop style="stop-color:#'.$color.';stop-opacity:0;" offset="1" /> </linearGradient> '; } foreach($paths as $i => $path) { echo ' <path id="line" stroke-width="2px" vector-effect="non-scaling-stroke" style="fill:url(#gradient'.$colors[$i].');stroke:#'.$colors[$i].';" d="'.$path.'" /> '; } ?> </svg> Feel free to use the code however and for whatever you want. ncc50446, +InsaneNutter, Depicus and 1 other 4 Share Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted October 23, 2014 Author Veteran Share Posted October 23, 2014 Here's another update with a bit cleaner code. <?php header('Content-type: image/svg+xml'); echo '<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'; if(isset($_GET["points"])) { $values = $_GET["points"]; $colors = $_GET["colors"]; } else { echo "<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"></svg>"; die(); } $paths = array(); $mergevalues = array(); foreach($values as $points) { $mergevalues = array_merge($mergevalues,$points); } $height = max($mergevalues); foreach($values as $i => $points) { $step = 100/(count($points)-1); $paths[$i] = $line = "m-10,".($height+10)." l0,-".($points[0]+10)." l10,0 "; foreach($points as $p => $point) { $paths[$i] .= "L".($p*$step).",".($height-$point)." "; } $paths[$i] .= "l10,".($points[count($points)-1]+10)." z"; } ?> <svg width="100%" height="100%" id="graph" version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 <?php echo $height;?>" preserveAspectRatio="none"> <?php foreach($colors as $color) { echo ' <linearGradient id="gradient'.$color.'" x1="0" y1="0" x2="0" y2="100%"> <stop style="stop-color:#'.$color.';stop-opacity:.3;" offset="0" /> <stop style="stop-color:#'.$color.';stop-opacity:0;" offset="1" /> </linearGradient> '; } foreach($paths as $i => $path) { echo ' <path id="line" stroke-width="2px" vector-effect="non-scaling-stroke" style="fill:url(#gradient'.$colors[$i].');stroke:#'.$colors[$i].';" d="'.$path.'" /> '; } ?> </svg> Link to comment Share on other sites More sharing options...
0 ncc50446 Posted December 16, 2014 Share Posted December 16, 2014 Thanks for that code! However I am slightly confused..When I plug in your code, I get a broken image..Never worked with svg files before..Is this only part of the code? I pretty much just copied your code, I didn't change anything. I assume that I need an image..Since no where in that code do I see anything about listing the months. Where would I put that? Thanks for any help! Link to comment Share on other sites More sharing options...
0 Shiranui Posted December 16, 2014 Share Posted December 16, 2014 So you are using php to generate svg code? Never thought of that. Might give it a try. Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted December 16, 2014 Author Veteran Share Posted December 16, 2014 Thanks for that code! However I am slightly confused..When I plug in your code, I get a broken image..Never worked with svg files before..Is this only part of the code? I pretty much just copied your code, I didn't change anything. I assume that I need an image..Since no where in that code do I see anything about listing the months. Where would I put that? Thanks for any help! Just save the code as graph.php then refer to it with a img tag like this: <?php $a = array(45,28,89,33,54,12,90,56,84,37,19,129); //points $colors = array("5677fc"); $points = array("points"=>array($a),"colors"=>$colors); ?> <img class="graph" src="graph.php?<?php echo http_build_query($points);?>" /> The months are not included in the code and are just html elements. I'll rewrite the graph with jslogo and include the months ^^ So you are using php to generate svg code? Never thought of that. Might give it a try. Yeah I'm also currently working on using js to generate svg code. https://www.neowin.net/forum/topic/1239360-svg-js-logo/ Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted December 16, 2014 Author Veteran Share Posted December 16, 2014 var graph = new jslogo("#jslogo"); var points = [100,28,89,33,54,12,90,56,84,37,19,129]; var max = Math.max.apply(Math, points); graph.pen("rgba(20,80,200,.7)"); graph.gradient("graph_bg","rgba(20,80,200,.1)","rgba(20,80,200,.4)",0); graph.fill("url(#graph_bg)"); graph.step(-10,0); graph.stepA(-10,(graph.height/max)*points[0]); for(x=0;x<points.length;x++) { graph.stepA(graph.width/(points.length-1)*x,(graph.height/max)*points[x]); } graph.stepA(graph.width,0); Here's the same code for jslogo, it's simpler in my opinion :P I'll add the months and also change the border thickness. Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted December 16, 2014 Author Veteran Share Posted December 16, 2014 (edited) Here's some jslogo code that also includes the axis: //Resize svg drawing //This code is not necessary and only used for changing some html on the jslogo site $("#jslogo")[0].setAttribute("viewBox","0 0 800 400"); $("#jslogo").css("width","800px"); $("#jslogo").css("height","400px"); //Disable grid bg //This code is not necessary and only used for changing some html on the jslogo site grid() //Properties and values var graph = new jslogo("#jslogo"); var points = [100,28,89,33,54,12,90,56,84,37,19,129]; var x_axis = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; //points.length must be equal with x_axis.length var padding = 50; var y_step_height = 40; //Draw graph var max = Math.max.apply(Math, points); graph.pen("none"); graph.step(padding,padding); graph.pen("rgba(20,80,200,.7)"); graph.gradient("graph_bg","rgba(20,80,200,0)","rgba(20,80,200,.2)",0); graph.fill("url(#graph_bg)"); graph.stepA(padding,((graph.height-2*padding)/max)*points[0]+padding); for(x=0;x<points.length;x++) { graph.stepA((graph.width-2*padding)/(points.length-1)*x+padding,((graph.height-2*padding)/max)*points[x]+padding); } graph.stepA(graph.width-padding,padding); graph.pen("none"); graph.fill("none"); //Draw graph border graph.stepA(padding,padding); graph.pen("#ddd"); graph.step(0,graph.height-2*padding); graph.step(graph.width-2*padding,0); graph.step(0,-graph.height+2*padding); graph.step(-graph.width+2*padding,0); graph.pen("none"); //Draw y-axis graph.stepA(padding-10,padding); var y_steps = Math.floor((graph.height-2*padding)/y_step_height); for(x=0;x<y_steps;x++) { graph.text(Math.round(max/y_steps*x),"#777","end"); graph.forward(y_step_height); } //Draw x-axis graph.stepA(padding,padding-20); graph.right(90); for(x=0;x<x_axis.length;x++) { graph.text(x_axis[x],"#777","middle"); graph.forward((graph.width-2*padding)/(x_axis.length-1)); } //Change font-size //This code is not necessary and only used for changing some css on the jslogo site $("#jslogo").css("font-size","12px"); You can try the code on http://seapip.com/jslogo/ Preview: I haven't added support yet for using background images in jslogo and using a different border width then 1px. Implementing jslogo is quite simple, download jslogo.js(requires jquery) and put on your site and then just start drawing with the logo syntax as shown above in the example. Edited September 21, 2015 by Seahorsepip Link to comment Share on other sites More sharing options...
0 pupils space Posted September 20, 2015 Share Posted September 20, 2015 Could we please have an update for some axis and there labels on the php generate svg graph? Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted September 21, 2015 Author Veteran Share Posted September 21, 2015 Could we please have an update for some axis and there labels on the php generate svg graph? What would you like to see changed/added? And do you prefer the php method or the js method? pupils space 1 Share Link to comment Share on other sites More sharing options...
0 pupils space Posted September 27, 2015 Share Posted September 27, 2015 (edited) This is an amazing piece of work that you have created here and will be really beneficial to my work. What would you like to see changed/added? And do you prefer the php method or the js method? If it is at all possible, for you to add axis to the chart with the axis labels; that would be awesome. Although I am not sure I am setting it up right because your example image shows axis and labels. Here is my example (live version found here http://pupil.space/test/linegraph.php): I would prefer you to use the PHP method; because, it reduces the amount of data which my client has to load; increasing the speed of the webpage. Thanks again, for your contribution. Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted September 27, 2015 Author Veteran Share Posted September 27, 2015 This is an amazing piece of work that you have created here and will be really beneficial to my work. If it is at all possible, for you to add axis to the chart with the axis labels; that would be awesome. Although I am not sure I am setting it up right because your example image shows axis and labels. Here is my example (live version found here http://pupil.space/test/linegraph.php): I would prefer you to use the PHP method; because, it reduces the amount of data which my client has to load; increasing the speed of the webpage. Thanks again, for your contribution. The axis labels were not part of the code but added manually with html elements, this is far from efficient I can try and see if I can add the text in the php code. But keep in mind that the js method is more bandwidth efficient since you're only loading points on every page refresh, the js files(jslogo.js and graph.js) are only loaded once and then cached ^^ pupils space 1 Share Link to comment Share on other sites More sharing options...
0 pupils space Posted September 28, 2015 Share Posted September 28, 2015 The axis labels were not part of the code but added manually with html elements, this is far from efficient I can try and see if I can add the text in the php code. But keep in mind that the js method is more bandwidth efficient since you're only loading points on every page refresh, the js files(jslogo.js and graph.js) are only loaded once and then cached ^^ It would be greatly appreciated if you could do this. Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted September 30, 2015 Author Veteran Share Posted September 30, 2015 It would be greatly appreciated if you could do this. Just went and gave it a try but there is a problem, When the labels are part of the svg the text is also transformed when the image is stretched, which means the text will be stretched with the graph So only thing that would work properly would be putting html tags with the labels which are positioned with css around the img that loads the svg. Link to comment Share on other sites More sharing options...
0 Seahorsepip Veteran Posted September 30, 2015 Author Veteran Share Posted September 30, 2015 (edited) It would be greatly appreciated if you could do this. Wrote a axis labels implementation in php with some css, the labels are generated on the page with the image html element itself.It was a bit tricky to have the labels positioned correctly and move correctly when the graph is resize but somehow I managed to do it. Preview: Code: <style type="text/css"> html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,abbr,address,cite,code,del,dfn,em,img,ins,kbd,q,samp,small,strong,sub,sup,var,b,i,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,figcaption,figure,footer,header,hgroup,menu,nav,section,summary,time,mark,audio,video { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; } article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section { display: block; } </style> <?php //Above css is just used to reset the css of the page, //not needed when using this code on your own site since I assume it has a css reset already $y_steps = 20;//The amount of steps to show in the y-axis $padding = 48;//Padding around the graph in px for the axis labels $distance = 10;//Distance between axis labels and the graph in px $a = array(45,28,89,33,54,12,90,56,84,37,19,129); $b = array(66,100,65,0,30,57,3,53,71,20,23,47); $x_axis = array("a","b","c","d","e","f","g","h","i","j","k","l"); $colors = array("5677fc","fbc157"); $points = array("points"=>array($a,$b), "x_axis"=>$x_axis, "colors"=>$colors); ?> <style type="text/css"> .graph_wrapper { position: relative; height: 100%; width: 100%; overflow: hidden; } .graph_wrapper .graph_img { border: 1px solid #eee; position: absolute; bottom: <?php echo $padding;?>px; left: <?php echo $padding;?>px; right: <?php echo $padding;?>px; top: <?php echo $padding;?>px; } .graph_wrapper .graph { margin: 0; width: 100%; height: 100%; } .graph_wrapper .y_axis { position: absolute; bottom: <?php echo $padding;?>px; top: <?php echo $padding;?>px; left: 0; width: <?php echo $padding;?>px; } .graph_wrapper .y_axis .label_wrapper { height: <?php echo 100/($y_steps);?>%; position: relative; } .graph_wrapper .y_axis .label_wrapper .label { text-align: right; line-height: 100%; height: 100%; position: absolute; right: <?php echo $distance;?>px; top: -50%; display: inline-block; vertical-align: middle; } .graph_wrapper .y_axis .label_wrapper .label:before { content: ''; display: inline-block; height: 100%; vertical-align: middle; } .graph_wrapper .x_axis { position: absolute; bottom: 0; left: <?php echo $padding;?>px; right: <?php echo $padding;?>px; height: <?php echo $padding;?>px; } .graph_wrapper .x_axis .label_wrapper { width: <?php echo 100/(count($x_axis)-1);?>%; float: left; height: <?php echo $padding;?>px; } .graph_wrapper .x_axis .label_wrapper .label { margin-left: -50%; margin-right: 50%; text-align: center; margin-top: <?php echo $distance;?>px; } .graph_wrapper .x_axis div:first-child { } .graph_wrapper .x_axis .label_wrapper:last-child { position: absolute; bottom: 0; right: <?php echo -100/(count($x_axis)-1);?>%; } </style> <div class="graph_wrapper"> <div class="graph_img"> <img class="graph" src="line_graph.php?<?php echo http_build_query($points);?>" /> </div> <div class="y_axis"> <?php $mergevalues = array(); foreach($points["points"] as $points) { $mergevalues = array_merge($mergevalues,$points); } $max = max($mergevalues); for($y=$y_steps;$y>=0;$y--){ echo "<div class=\"label_wrapper\"><div class=\"label\">".round($max/$y_steps*$y)."</div></div>"; } ?> </div> <div class="x_axis"> <?php foreach($x_axis as $x=>$label) { echo "<div class=\"label_wrapper\"><div class=\"label\">$label</div></div>"; } ?> </div> </div> ncc50446 1 Share Link to comment Share on other sites More sharing options...
Question
Seahorsepip Veteran
I was looking for a simple way of making a line graph with svg.
Since I did not really want to include yet another library for something that seemed quite simple I decided to write something myself.
After some fiddling around I came up with the following php file which returns a svg graph based on the url parameter values you pass to it:
As example I use it like this:
What do you guys think? Is this a bad or a good idea? Anything to improve?
I'm thinking about making it possible to add multiple lines.
Oh and here's a image of the graph :
Link to comment
Share on other sites
14 answers to this question
Recommended Posts