How can I make double click event on node in d3.js? - svg

I want to make double click event on nodes.
So I tried
.on("dbclick",function(d){return "http://google.com");});
and
.bind({"dbclick",function(d){alert("hello")} });
But all failed. Can anyone help me?
Full codes are below.
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
//.on("dbclick",function(d){return "http://google.com");});
//.attr("xlink:href", function(d){return d.url;}
.call(force.drag);
//.bind({"dbclick",function(d){alert("hello")} });
Finally, I used a below method. (dblclick also works)
var node = svg.selectAll(".node") .data(graph.nodes) .enter().append("a")
.attr("class", "node") .attr("target", "_blank")
.attr("xlink:href", function(d){return "google.com";;})

You can use "dblclick" instead of "dbclick":
nodes.on("dblclick",function(d){ alert("node was double clicked"); });

If using D3 Observable:
const nodeEnter = node.enter().append("g")
.on("dblclick", d => {
d3.event.preventDefault();
// do your thing
});

Related

How to generate SVG using dimple in Node.js

Here my question is very simple,
I need to generate SVG using dimple in Node.js.
And i installed this node module npm install dimple-js but there is no proper documentation for this ?
i have tried this below code:
var jsdom = require("node-jsdom");
globals = {};
global.window = jsdom.jsdom().parentWindow;
global.document = jsdom.jsdom('<!doctype html></html>');
var d3 = require('dimple-js/lib/d3.v3.4.8.js');
var dimple = require('dimple-js/dist/dimple.v2.1.6.js');
module.exports = function(router){
router.get('/', function(req, res){
var svg = dimple.newSvg('body', 800, 600);
var data = [
{ "Word":"Hello", "Awesomeness":2000 },
{ "Word":"World", "Awesomeness":3000 }
];
var myChart = new dimple.chart(svg, data);
myChart.addCategoryAxis("x", "Word");
myChart.addMeasureAxis("y", "Awesomeness");
myChart.addSeries(null, dimple.plot.bar);
myChart.draw();
res.json({success: true, svg: svg});
});
}
but am getting below error
So is that possible to generate SVG using dimple in server side ?
dimple (or in fact, d3) can't find the DOM. Use this pattern, like at the bottom of this page:
var svg = d3.select(global.document.body)
.append("svg")
.attr("width", 800)
.attr("height", 600);

setZoom and getZoom are undefined

I have created a canvas object but when I try to use getZoom() and setZoom it says that they are undefined.
canvas = new fabric.Canvas();
new fabric.Image.fromURL(url, function (omg){
canvas.add(omg);
});
canvas.setZoom(canvas.getZoom()*1.1);
Am I doing something wrong?
You need to update fabric.js version to 1.4.13. You can download here: https://rawgit.com/kangax/fabric.js/master/dist/fabric.js
Zoom X 2:
var canvas = new fabric.Canvas('canvas');
var url = "http://serio.piiym.net/CVBla/txtboard/thumb/1260285874089s.jpg";
fabric.Image.fromURL(url, function (img){
img.left = 80;
img.top = 50;
canvas.add(img);
});
canvas.renderAll();
alert(canvas.getZoom());
canvas.setZoom(canvas.getZoom()*2);
canvas.renderAll();
alert(canvas.getZoom());
I have made a fiddle for you: http://jsfiddle.net/tdzoygc4/1/
Hope that helps.

D3js: how to generate standalone SVG files? (Nodejs)

Given a D3js code, such as:
var square= function() {
var svg = window.d3.select("body")
.append("svg")
.attr("width", 100)
.attr("height", 100);
svg.append("rect")
.attr("x", 10)
.attr("y", 10)
.attr("width", 80)
.attr("height", 80)
.style("fill", "orange");
}
square();
svg { border: 1px solid grey;} /* just to visualized the svg file's area */
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<body></body>
How to generate a correct stand alone *.svg file with my D3js code & NodeJS ?
Github repository svgcreator.node.js to try out.
D3 doesn't care at all what actually generate your SVG. The main problem with creating only SVG is that you can't have Javascript then, which of course means that you can't use D3. Apart from this fundamental no-no, there's nothing stopping you :)
Proof of concept: Inspired by the other answer, here's some proof-of-concept code using jsdom.
1. Install NodeJS (1).
curl http://npmjs.org/install.sh | sh #this should work (not tested)
2. Install jsdom using the Node Packages Manager (2):
$npm install jsdom
3. Wrap your D3js code within some jsdom code, paste into a jsdom.node.js file :
var jsdom = require('jsdom');
jsdom.env(
"<html><body></body></html>",
[ 'http://d3js.org/d3.v3.min.js' ],
function (err, window) {
var svg = window.d3.select("body")
.append("svg")
.attr("width", 100).attr("height", 100);
svg.append("rect")
.attr("x", 10)
.attr("y", 10)
.attr("width", 80)
.attr("height", 80)
.style("fill", "orange");
// PRINT OUT:
console.log(window.d3.select("body").html());
// fs.writeFileSync('out.svg', window.d3.select("body").html()); // or this
}
);
4. Run in terminal
$node jsdom.node.js > test.svg
The stdout output is the SVG, which is then injected into a test.svg file. Job done.
As Gilly points out in the comments, you may need version 3 of jsdom for this to work.
Here's a very short node script that will output an svg to stdout generated with d3.js.
#!/usr/bin/env node
var d3 = require("d3"),
jsdom = require("jsdom").jsdom;
var body = d3.select(jsdom().documentElement).select("body");
var svg = body.append("svg");
process.stdout.write(body.node().innerHTML);
Link to snippet on bl.ocks.org
I recently wanted to do just that and asked a question here. I was pointed to phantomJS. Using PhantomJS, I created a JS -
svggen.js:
var page = require('webpage').create(),
url = 'http://www.example.com/wordcloud.html';
page.open(url, function (status) {
if (status !== 'success') {
console.log('Unable to access network');
} else {
var svgData = page.evaluate(function(s){
var serializer = new XMLSerializer();
var element = document.getElementById("svg1");
return serializer.serializeToString(element);
});
console.log("<?xml version=\"1.0\"?>"+svgData);
}
phantom.exit();
});
wordcloud.html:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="d3.min.js"></script>
<script src="d3.layout.cloud.js"></script>
<script>
var fill = d3.scale.category20();
d3.layout.cloud().size([500, 800])
.words([
"Hello", "world", "normally", "you", "want", "more", "words",
"than", "this"].map(function(d) {
return {text: d, size: 10 + Math.random() * 90};
}))
.padding(5)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return d.size; })
.on("end", draw)
.start();
function draw(words) {
d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 800)
.attr("id","svg1")
.attr("xmlns","http://www.w3.org/2000/svg")
.attr("xmlns:xlink","http://www.w3.org/1999/xlink")
.append("g")
.attr("transform", "translate(150,150)")
.selectAll("text")
.data(words)
.enter().append("text")
.style("font-size", function(d) { return d.size + "px"; })
.style("font-family", "Impact")
.style("fill", function(d, i) { return fill(i); })
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
})
.text(function(d) { return d.text; });
}
</script>
</body></html>
Then I run
phantomjs svggen.js > svgFile.svg
The resulting svgFile.svg is a standalone SVG File. For d3cloud check this.
node.js is the way to go. You can install d3 directly with npm. (It will also add jsdom as a dependency to provide a "fake" DOM.) After the d3 code generates the SVG, just grab its contents and write to a file.
if you donot want to use node.js , then use phantomJs , here you can find a demo
https://github.com/subramanya2107/d3js-phantomjs-demo.git

Three.js with Node.js on a server - how to load a TEXTURE?

I have a trouble with Three.js for loading a texture and applying to a mesh cube.
In local, I know there are some issues like running the html file on a apache server with wamp (localhost).
But when I use Node.js and socket.io, how to fix it ?
First, to load three.js, I have to put the web adress of the script src instead of a local "three.js" :
http://threejs.org/build/three.min.js
It works but how about the texture ?
Neither a local or an internet adress for the texture is working...
//var mapUrl = "mercury.jpg";
var mapUrl = "http://threejs.org/examples/textures/cube/skybox/px.jpg";
var map = THREE.ImageUtils.loadTexture(mapUrl); // its not working with both
And if I put my code on a web server running with Node.js like Cloud9, how to fix it ? (same problem as in local with Node.js).
Thank you for your attention.
Here is my complete code.
Server
var http = require('http');
var fs = require('fs');
// Creation du serveur
var app = http.createServer(function (req, res) {
// On lit notre fichier app.html
fs.readFile('gl.html', 'utf-8', function(error, content) {
res.writeHead(200, {'Content-Type' : 'text/html'});
res.end(content);
});
});
var io = require("socket.io");
io = io.listen(app);
io.sockets.on('connection', function (socket) {
socket.on('send', function () {
socket.broadcast.emit('rec');
}); // send
}); // connection
app.listen(8080);
Client (gl.html)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to WebGL</title>
</head>
<body onLoad="onLoad();" style="">
<h1>Webgl</h1>
<div id="container" style="width:95%; height:80%; position:absolute;"></div>
<script type="text/javascript" src="http://threejs.org/build/three.min.js"></script>
<!--<script type="text/javascript" src="Three.js"></script> not working-->
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
var renderer = null,
scene = null,
camera = null,
cube = null,
animating = false;
function onLoad()
{
// Grab our container div
var container = document.getElementById("container");
// Create the Three.js renderer, add it to our div
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize(container.offsetWidth, container.offsetHeight);
container.appendChild( renderer.domElement );
// Create a new Three.js scene
scene = new THREE.Scene();
// Put in a camera
camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 4000 );
camera.position.set( 0, 0, 3 );
// Create a directional light to show off the object
var light = new THREE.DirectionalLight( 0xffffff, 1.5);
light.position.set(0, 0, 1);
scene.add( light );
// Create a shaded, texture-mapped cube and add it to the scene
// First, create the texture map
// var mapUrl = "mercury.jpg";
var mapUrl = "http://threejs.org/examples/textures/cube/skybox/px.jpg";
var map = THREE.ImageUtils.loadTexture(mapUrl); // not working with both !!!
// Now, create a Phong material to show shading; pass in the map
var material = new THREE.MeshPhongMaterial({ map: map });
// Create the cube geometry
var geometry = new THREE.CubeGeometry(1, 1, 1);
// And put the geometry and material together into a mesh
cube = new THREE.Mesh(geometry, material);
// Turn it toward the scene, or we won't see the cube shape!
// cube.rotation.x = Math.PI / 5;
cube.rotation.x = 0.5;
//cube.rotation.y = Math.PI / 5;
// Add the cube to our scene
scene.add( cube );
// Add a mouse up handler to toggle the animation
addMouseHandler();
// Run our render loop
run();
}
function run()
{
// Render the scene
renderer.render( scene, camera );
// Spin the cube for next frame
if (animating)
{
cube.rotation.y -= 0.01;
//cube.rotation.x += 0.05;
}
// Ask for another frame
//requestAnimationFrame(run);
setTimeout(run, 1000/60);
}
function addMouseHandler()
{
var dom = renderer.domElement;
dom.addEventListener( 'mouseup', onMouseUp, false);
}
function onMouseUp (event)
{
event.preventDefault();
animating = !animating;
socket.emit('send');
}
socket.on('rec', function () {
animating = !animating;
});
</script>
</body>
</html>
In fact i just had to use express, place all the files in the folder public and name client index.html.
Now it works ! How can close my question ?
Here is the simple code of the server :
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(8080);
You are running into trouble with CORS. CORS state that textures need to be comming from the same base url or needs special handling on server side. This is easily fixable with a proxy. If you are already using a server thaen it shouldn't be too hard to configure it to handle proxy requests.

How to use D3 in Node.js properly?

I've been trying to invoke D3 within Node.js. I tried firstly to import d3.v2.js from D3's website with the script tag, but then read this thread:
I want to run d3 from a Cakefile
Where D3's author advises one should 'npm install d3'...I did this, and I can successfully invoke it in node console:
dpc#ananda:$ node
> var d3 = require("d3");
undefined
> d3.version;
'2.8.1'
However, when trying to invoke it from app.js with 'node app.js', I get:
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Cannot read property 'BSON' of undefined
at /Users/dpc/Dropbox/sync/Business/MindfulSound/Development/nad.am/nadam/node_modules/mongoose/node_modules/mongodb/lib/mongodb/index.js:45:44
I realise that elsewhere, D3's author has clearly specified that one should require the canvas:
https://github.com/mbostock/d3/blob/master/examples/node-canvas/us-counties.js
as:
var Canvas = require("canvas");
but even then, (and even if specifically requiring index.js instead of d3.v2.js in a require statement in app.js), I can't get the below to work within a Jade template:
- script('/javascripts/d3.v2.js')
h1 Dashboard
section.css-table
section.two-column
section.cell
hr.grey
h2 Statistics
#mainGraph
script(type="text/javascript")
var Canvas = require("canvas");
var w = 400,
h = 400,
r = Math.min(w, h) / 2,
data = d3.range(10).map(Math.random).sort(d3.descending),
color = d3.scale.category20(),
arc = d3.svg.arc().outerRadius(r),
donut = d3.layout.pie();
var vis = d3.select("body").append("svg")
.data([data])
.attr("width", w)
.attr("height", h);
var arcs = vis.selectAll("g.arc")
.data(donut)
.enter().append("g")
.attr("class", "arc")
.attr("transform", "translate(" + r + "," + r + ")");
var paths = arcs.append("path")
.attr("fill", function(d, i) { return color(i); });
paths.transition()
.ease("bounce")
.duration(2000)
.attrTween("d", tweenPie);
paths.transition()
.ease("elastic")
.delay(function(d, i) { return 2000 + i * 50; })
.duration(750)
.attrTween("d", tweenDonut);
function tweenPie(b) {
b.innerRadius = 0;
var i = d3.interpolate({startAngle: 0, endAngle: 0}, b);
return function(t) {
return arc(i(t));
};
}
function tweenDonut(b) {
b.innerRadius = r * .6;
var i = d3.interpolate({innerRadius: 0}, b);
return function(t) {
return arc(i(t));
};
section.cell
hr.grey
h2 Achievements
The correct way to use D3 within Node is to use NPM to install d3 and then to require it. You can either npm install d3 or use a package.json file, followed by npm install:
{
"name": "my-awesome-package",
"version": "0.0.1",
"dependencies": {
"d3": "3"
}
}
Once you have d3 in your node_modules directory, load it via require:
var d3 = require("d3");
And that's it.
Regarding your other issues: Canvas is not required to use D3. The node-canvas example you linked requires canvas because it renders to a canvas. The TypeError (Cannot read property 'BSON' of undefined) appears to be related to your use of mongoose / monogdb, not D3.
To use with ES6's import instead of require:
import * as d3 from 'd3';
This is perhaps obvious to any experienced babel/ES6-user, and I know this is an old question, but I came here in an attempt to figure this out. Hope this is helpful for someone.
More on import vs. require is found here.
You need to install jsdom using yarn or npm.
Node.js does not support dom by default, thus the need to use jsdom for creating dom elements. Use d3 for all other manipulations except fetch operations. i.e d3.xml,d3.tsv
import jsdom from 'jsdom';
import * as d3 from 'd3';
const { JSDOM } = jsdom;
JSDOM.fromURL(
'your resource url',
).then((dom) => {
const doc = dom.window.document;
const states = d3
.select(doc)
.select('path')
.attr(':fme:ID');
console.log(states);
});
creating dom from file
JSDOM.fromURL(
'your resource url',
).then((dom) => {
const doc = dom.window.document;
}
dom from html string
const dom = new JSDOM(
`<p>Hello
<img src="foo.jpg">
</p>`,
{ includeNodeLocations: true }
);

Resources