Plot dimple(d3.js) chart in deck.js section - svg

I would like to insert a dimple plot into a deck.js presentation. The code below online puts the plot in the body at the background. But I would like to have the plot displayed in the section class. I think I have to change something in var svg = dimple.newSvg("body", 800, 600). Because of my very limited javascript skills I have no idea what to change exactly. Any help would be very much appreciated.
<section class="slide" id="test-section">
<h2>test section</h2>
<script type="text/javascript">
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v1.min.js"></script>
var svg = dimple.newSvg("body", 800, 600);
var data = [
{ "Word":"Hello", "Awesomeness":2000 },
{ "Word":"World", "Awesomeness":3000 }
];
var chart = new dimple.chart(svg, data);
chart.addCategoryAxis("x", "Word");
chart.addMeasureAxis("y", "Awesomeness");
chart.addSeries(null, dimple.plot.bar);
chart.draw();
</script>
</section>
If only the included the specific section class code in my question. If needed the complete code can be found here. The index page in the is located in the introduction folder.

A couple things need fixing:
First, you can't put a script tag inside of another script tag. You should move the code that loads d3 and dimple to the head of the document:
...
<script src="../modernizr.custom.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v1.min.js"></script>
</head>
Second, as you suspected and John points out, something with dimple.newSvg is wrong. You probably want var svg = dimple.newSvg("#test-section", 800, 600); so the graph is only added to the test-selection slide, not all of the slides.
I would actually go one step farther and change the html a little bit so you can control precisely where the graph appears:
<h2>Graph Title</h2>
<div id = "graphHere"></div>
<h3>Some more text about the graph below the graph</h3>
To make the graph appear between the text, just change the selection passed to dimple to the id of the div we've created:
var svg = dimple.newSvg("#graphHere", 800, 600);
Finally, chart.js is doing some weird resizing the graph since it is too big to fit on the slide. Without digging through the source of chart.js, we can fix the problem by creating a smaller graph:
var svg = dimple.newSvg("#graphHere", 400, 200);

I like the look of deck.js so I just pulled it down and had a play. I then came back and found Adam had basically explained everything I just found out. You need to put a div within the slide and add the svg to that, otherwise the deck scaling code duplicates the chart.
First add a div to the relevant slide:
<section class="slide">
<div id="myChartDiv"></div>
</section>
Then add the references to the set at the bottom (or the header if you like):
<!-- Required JS files. -->
<script src="jquery-1.7.2.min.js"></script>
<script src="core/deck.core.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://dimplejs.org/dist/dimple.v1.min.js"></script>
then the dimple code below that:
<script type="text/javascript">
var svg = dimple.newSvg("#myChartDiv", 800, 600);
var data = [
{ "Word":"Hello", "Awesomeness":2000 },
{ "Word":"World", "Awesomeness":3000 }
];
var chart = new dimple.chart(svg, data);
chart.addCategoryAxis("x", "Word");
chart.addMeasureAxis("y", "Awesomeness");
chart.addSeries(null, dimple.plot.bar);
chart.draw();
</script>
I hope that hopes
John

I've never used deck.js but have you tried:
var svg = dimple.newSvg(".slide", 800, 600);
or
var svg = dimple.newSvg("#test-section", 800, 600);
Let me know if that works. If not I'll take a look at your code.

I know that this thread is from a long time ago, but let me add one thing in addition to Adam's answer.
At least on dimple v2.1.2 + deck.js v1.1.0 + Firefox 34.0, the graph is corrupted in Adam's example.
It seems that the size of the div tag must be explicitly set:
<div id="graphHere" style="width:400px;height:300px;"></div>
...
<script>
var svg = dimple.newSvg("#graphHere", 400, 300);
// plotting function goes here
</script>

Related

svg convert to canvas - can't generate multi pages pdf

I have 12 graphs and I want to generate pdf with 2 pages each page has 6 graphs.
However, when I convert svg to canvas, then the jspdf can only see part of both sub-dives.
$('#downloadx2').click(function() {
var svgElements = $("#body_id").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function() {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function(index, el) {
$(this).css('font-size', getStylex(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
var doc = new jsPDF("p", "mm");
var width = doc.internal.pageSize.width;
var height = doc.internal.pageSize.height;
html2canvas($("#div_pdf1"), {
onrendered: function(canvas) {
var imgData = canvas.toDataURL(
'image/png', 0.1);
doc.addImage(imgData, 'PNG', 5, 0, width, height/2,'','FAST');
doc.addPage();
}
});
html2canvas($("#div_pdf2"), {
onrendered: function(canvas2) {
var imgData2 = canvas2.toDataURL(
'image/png', 0.1);
doc.addImage(imgData2, 'PNG', 5, 0, width, height/2,'','FAST');
doc.save('.pdf');
}
});
});
<body id="body_id">
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
</body>
When I run this code, the generated pdf will view two pages with same canvas the first one (div_pdf1) div. So how to get both of them appearing in pdf as two pages.
You seem to be trying to run 2 parts in sequence but that's not how javascript works and actually runs your code.
No big deal, just a small misunderstanding between your mental model and the engine that executes the code.
A quick temporary debugging tool to see what's going on and verify that there is a discrepancy is to add console.log to key points and check the sequence of their printout once you run the code.
console.log('[1] just before: svgElements.each');
svgElements.each(function() {
console.log('[2] just after: svgElements.each');
And also around this part of the code:
console.log('[3] just before html2canvas-div_pdf1');
html2canvas($("#div_pdf1"), {
console.log('[4] just after html2canvas-div_pdf1');
Finally around this part of the code:
console.log('[5] just before html2canvas-div_pdf2');
html2canvas($("#div_pdf2"), {
console.log('[6] just after html2canvas-div_pdf2');
I suspect you'll see the code doesn't print the log lines in the order you think they will.
Next, you can try wrapping the 2 calls to html2canvas with one setTimeout function and force a delay in the execution of that code by an arbitrary amount of milliseconds.
Note that this is not the recommended final production quality solution but it will make the code output what you want.

Do not render chart when no data is found or display a message or something similar

I'm using the drilldown pie chart to drill down into children of a node, etc. The problem is that at some point, the children do not contain any data. Is there a way to display a message or something similar inside the chart instead of a white area (because of no series data) that informs the user that there is no more data to display?
Very good question! Inside of your JSON configuration you can define the nodata attribute.
var myConfig = {
type: "bar",
noData:{
text:"Empty Series",
backgroundColor: "#20b2db"
},
series:[
{
values:[]
}
]
};
zingchart.render({
id : 'myChart',
data : myConfig,
height: 400,
width: 600
});
<!DOCTYPE html>
<html>
<head>
<script src= "https://cdn.zingchart.com/zingchart.min.js"></script>
</head>
<body>
<div id='myChart'></div>
</body>
</html>
You can even use background image like a loading screen. In the following example I'm displaying spongebob while I'm waiting for chart data to come in. So I initially render a chart with no series values and nodata defined. The image is displayed while the Ajax call happens asynchronously.
demo

Google Earth Plugin, embedded in Blogger, producing 2 maps

Curious problem whilst embedding a Google Earth network link into Blogger.
The code I'm using is as shown below, but I'm getting two instances of GE on the same page, one above the other.
They must be getting generated seperately, as if I stick a border into the divs style on the page it only affects one instance.
<div id="map3d" style="border: 4px solid silver; height: 768px; width: 1024px;"></div>
However, if I remove this code from the page entirely. both instances vanish.
Other than that I've got it functioning as I'm wanting. (Eventually)
This is the code I've got in the head section
<!-- Earth -->
<script src="//www.google.com/jsapi?key=mykey"></script>
<script type="text/javascript">
var ge;
google.load("earth", "1", {"other_params":"sensor=false"});
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
ge.getNavigationControl().setVisibility(ge.VISIBILITY_SHOW);
var href = 'http://urltomykmz';
google.earth.fetchKml(ge, href, function(kmlObject) {
if (kmlObject)
ge.getFeatures().appendChild(kmlObject);
if (kmlObject.getAbstractView() !== null)
ge.getView().setAbstractView(kmlObject.getAbstractView());
});
}
function failureCB(errorCode) {
}
google.setOnLoadCallback(init);
</script>
<!-- Earth -->
Grateful to anyone who can point to what's causing the second instance. Thanks.
You have to remove either the call to init() in your onload handler or the call to google.setOnLoadCallback(init), otherwise a map will be added every time you call the init function.

Is it possible to change clipart color programmatically?

I would like to know if it is possible to change clipart color in html5 canvas. I couldn't find any information about it, but I have seen a designer's software that is able to implement this function. Thank you in advance!
Yes, you can use html canvas to change selected colors on an image.
Here's how:
You can use canvas's getImageData to read the RGBA value of any pixel(s) on the canvas:
// get the pixel at the click position
var imgData=ctx.getImageData(mouseX,mouseY,1,1);
var data=imgData.data;
// the R,G,B of the clicked color are in sequential elements of the data[] array
var Red=data[0];
var Green=data[1];
var Blue=data[2];
Then to replace a color, you can loop through the canvas’s entire pixel array and replace the clicked color with a new color of your choice:
// test
// replace the clicked color with Gold
var newR=255;
var newG=215;
var newB=0;
// get the pixel array for the whole canvas
var imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
var data=imgData.data;
// loop through all pixels on the canvas
for(var i=0;i<data.length;i+=4) {
// if this pixel matches the old color, replace it
if(data[i]==oldR && data[i+1]==oldG && data[i+2]==oldB){
data[i]= newR;
data[i+1]= newG;
data[i+2]= newB;
}
}
And finally, when you’ve replaced all the colors, use ctx.putImageData to draw the modified pixels back on the canvas.
// put the recolored image back on the canvas
ctx.putImageData(imgData,0,0);
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/LZUfB/
<!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(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var img=new Image();
img.onload=function(){
canvas.width=img.width;
canvas.height=img.height;
ctx.drawImage(img,0,0);
}
// make sure to use crossOrigin="anonymous" to avoid CORS errors
// the image must be hosted on a CORS enabled site
img.crossOrigin="anonymous";
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/colorhouse.png";
// when the user clicks, change the clicked color to Gold
$("#canvas").click(function(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// get the pixel at the click position
var imgData=ctx.getImageData(mouseX,mouseY,1,1);
var data=imgData.data;
// if the clicked color is transparent, no work to do
if(data[3]<10){return;}
// save the R,G,B of the clicked color
var oldR=data[0];
var oldG=data[1];
var oldB=data[2];
// test
// replace the clicked color with Gold
var newR=255;
var newG=215;
var newB=0;
// get the pixel array for the whole canvas
var imgData=ctx.getImageData(0,0,canvas.width,canvas.height);
var data=imgData.data;
// loop through all pixels on the canvas
for(var i=0;i<data.length;i+=4) {
// if this pixel matches the old color, replace it
if(data[i]==oldR && data[i+1]==oldG && data[i+2]==oldB){
data[i]= newR;
data[i+1]= newG;
data[i+2]= newB;
}
}
// put the recolored image back on the canvas
ctx.putImageData(imgData,0,0);
});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

SVG shapes added to Raphael group fire events as if separate

Imagine this:
2 concentric circles, with the smaller one over the larger one so
that both are visible
both are added to a Raphael group (set)
the group has mouseout and mouseover event handlers
Problem:
When the cursor goes from one circle to the other, both event handlers fire, as if they were added separately to each circle.
What I want is for events to be handled for the entire group as if it was a single shape.
How can I achieve that?
Here's the html code:
<!DOCTYPE html>
<html>
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.0.0/raphael-min.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
<div id="target"></div>
</body>
</html>
Javascript:
var W=200;
var H=200;
var paper=new Raphael(document.getElementById('target'),W,H);
var c1=paper.circle(W/2,H/2,70).attr({fill:'orange','stroke-width':4,stroke:'red',opacity:0.7});
var c2=paper.circle(W/2,H/2,50).attr({fill:'green','stroke-width':4,stroke:'yellow',opacity:0.7});
var group=paper.set();
group.push(c1,c2);
var count=0;
group.mouseover(function()
{
console.log('IN',++count);
});
group.mouseout(function()
{
console.log('OUT',++count);
});
and the CSS code:
#target{width:200px;}
Run the above code and see the results here: http://jsbin.com/ivules/7.
Console shows IN and OUT logs.
Just move the mouse between the two circles' bounds.
For your mouseout() function, please try:
group.mouseout(function()
{
this.mouseout(function(){
console.log('OUT',++count);
});
});
When you hover over the outer circle, you will get "IN". When you hover over the inner circle, you will get "IN" again. When you leave the circle entirely, you will finally get "OUT".
If that's too many "IN"'s, try creating an invisible circle, place it over top the current 2 circles, and only add the mouseover event to that circle. For instance, try:
c3=paper.circle(W/2,H/2,70).attr({fill:'orange','stroke-width':4,stroke:'red',opacity:0});
c3.mouseover(function()
{
console.log('IN',++count);
});
c3.mouseout(function()
{
console.log('OUT',++count);
});

Resources