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 }
);
Related
I'm trying make a animated banner to discord server, but I have some problems with that. I don't know why document is not defined. I tried a bunch of ways, but none of them worked.
try {
let guild = await client.guilds.cache.get(guildId.id);
const voiceChannels = guild.channels.cache.filter((c) => c.type === "GUILD_VOICE");
let count = 0;
for (const [, voiceChannel] of voiceChannels) count += voiceChannel.members.size;
var canvas = createCanvas(420, 236);
var ctx = canvas.getContext('2d');
ctx.textAlign = "center"
ctx.font = "20px Kanit Black"
ctx.fillStyle = '000001'
const encoder = new GIFEncoder(420, 236, {emptyColor: true, dynamicColors: true})
encoder.setRepeat(0);
encoder.setQuality(10)
await gifFrames({ url: `${__dirname}/banner-beta.gif`, frames: 'all', outputType: 'canvas', cumulative: false}).then((frameData) => {
for(let i = 0; i < frameData.length; i++) {
encoder.setDelay(frameData[i].frameInfo.delay * 15);
console.log(frameData[0])
console.log(frameData[i])
ctx.drawImage((frameData[i]).getImage(), 0, 0, 420, 236)
ctx.fillText(`${count}`, 50, 90)
console.log(ctx)
encoder.addFrame(ctx);
}
encoder.finish();
console.log(encoder.out.getData())
var attachment = new MessageAttachment(encoder.out.getData(), 'banner.gif');
guild.channels.cache.get("909860310171648050").send({ files: [attachment] }).catch(console.log);
})
//guild.setBanner(canvas.toBuffer()).catch(console.error);
} catch (e) {
console.log(e)
}
error:
ReferenceError: document is not defined
at savePixels (C:\Users\hotab\Desktop\Root\node_modules\save-pixels-jpeg-js-upgrade\save-pixels.js:127:20)
at Object.getImage (C:\Users\hotab\Desktop\Root\node_modules\gif-frames\gif-frames.js:105:20)
at C:\Users\hotab\Desktop\Root\utils\banner.js:31:34
TL;DR:
Your code runs in NodeJS, in which there is no document object because it does not make sense on a backend server. So using document results in an exception.
More details
You are using the node module gif-frames that depends on another node module called save-pixels-jpeg-js-upgrade which tries to access the document object that only exists in a browser context (see code here).
Either the documentation of gif-frames stating that it can run in both Node and browsers contexts is incorrect or there are some restrictions to some APIs, which you are facing here. Based on the node module code, it seems to be limited to the CANVAS case, but I can't help you any further...
I'm trying to make a JS effect on Spark AR with a code and Native UI and also face mesh.
The effect have bottons to choose the effect, one of them have a face mesh where the texture is not recognize and the another one have a simple texture.
----- My code to script of two objects / two bottons:
const Materials = require('Materials');
const Scene = require('Scene');
const NativeUI = require('NativeUI');
const Textures = require('Textures');
const plane = Scene.root.find('plane0');
const index = 0;
const configuration = {
selectedIndex: index,
items: [
{image_texture: Textures.get('N1')},
{image_texture: Textures.get('N2')},
],
mats: [
{material: Materials.get("N1")},
{material: Materials.get("N2")},
]
};
const picker = NativeUI.picker;
picker.configure(configuration);
picker.visible = true;
picker.selectedIndex.monitor().subscribe(function(val) {
plane.material = configuration.mats[val.newValue].material;
;
});
----- The error message that shows when I open Spark AR Studio:
ERROR: undefined is not a function
{ "line": 6,
<br> "column": 30,
<br> "sourceURL": "scrip2obj.js"
}
I would like to know... what can I do to make this run and make the face mesh shows in the effect?
Starting from v85 of Spark AR Studio the current JavaScript APIs are deprecated in favor of asynchronous APIs.
This means some APIs will be deprecated and will need to be replaced in your projects. When creating new projects, new APIs should be used instead.
You can learn more about it here
Scripting Javascript Promise In Spark AR For Beginners
Try the following code to implement Native UI Picker
const Materials = require('Materials');
const NativeUI = require('NativeUI');
const Textures = require('Textures');
const Scene = require('Scene');
(async function () { // Enables async/await in JS [part 1]
// To access scene objects
const [plane0, n1, n2, n1Material] = await Promise.all([
Scene.root.findFirst('plane0'),
Textures.findFirst('N1'),
Textures.findFirst('N2'),
Materials.findFirst("N1"),
]);
const index = 0;
const configuration = {
selectedIndex: index,
items: [
{ image_texture: n1 },
{ image_texture: n2 },
]
};
const picker = NativeUI.picker;
picker.configure(configuration);
picker.visible = true;
picker.selectedIndex.monitor().subscribe(function (val) {
plane.material = configuration.mats[val.newValue].material;
});
})(); // Enables async/await in JS [part 2]
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);
Did someone of you try to make svg.js work with node.js? I tried to use the jsdom module to render svg but jsdom but SVG.supported returns false. Is there a way to make this library work with node.js?
Thanks in advance!
EDIT: Here is my code, I want to make that on Node.js and then probably render the SVG in a pdf or as a png:
var draw = SVG('drawing').size(600, 600)
var image = draw.image('inclusions.png')
image.size(400, 150)
var rect = draw.rect(400, 150).attr({ fill: 'orange' })
for (i = 0; i < 10; i++) {
var point = draw.circle(5)
var xpos = Math.floor((Math.random() * 400) + 1);
var ypos = Math.floor((Math.random() * 150) + 1);
point.x(xpos)
point.y(ypos)
point.fill('black')
}
image.front()
Here is the working example usage of svg.js inside nodejs project,
svgdom is the suggested library from svg.js official website
const window = require('svgdom');
const SVG = require('svg.js')(window);
const document = window.document;
function generateSVGTextLines(width, height, lineList, tAsset) {
var draw = SVG(document.documentElement).size(width, height);
draw.clear();
draw.text(function (add) {
if (lineList) {
for (var i = 0; i < lineList.length; i++) {
add.tspan(lineList[i].text).attr("x", "50%").newLine();
}
}
}).font({
family: tAsset.fontFamily,
size: tAsset.fontHeight,
leading: '1.2em',
anchor: "middle"
}).move(width / 2, 0);
return draw.svg();
}
This link might be helpful: http://techslides.com/save-svg-as-an-image
This documents a client side solution that causes the requisite SVG to be drawn on the end user's browser, rather than on the server, but it provides the end result you want by putting the SVG into an image tag and allowing the user to download it. If keeping the SVG drawing logic secret is a problem, you could use a similar principle by sicing PhantomJS on the generator page and sending the user the image it downloads.
var json = [];
json.push(json2);
function makeallImage(){
console.log('json length'+json.length);
for (var v = 0; v < json.length; v++){
convertImgToBase64(v, "jpg");
console.log("ksana"+v);
}
}
function convertImgToBase64(number, outputFormat){
var tmpData =
canvas.loadFromJSON(json[number], canvas.renderAll.bind(canvas), function(){
**//need to absolute comfirm it add all object in canvas, load complete json2 //**
canvas.on('object:added', function(e) {
toImg();
});
});
}
function toImg(outputFormat){
var s = document.getElementById("last_Image");
var url = canvas.toDataURL();
var newImg = document.createElement("img"); // create img tag
console.log(newImg);
newImg.src = url;
newImg.width = 100;
newImg.height = 100;
s.appendChild(newImg);
console.log('mpike sto dom');
}
i am using this code to create image to field , problem is if my json object contain image ,it will create empty image. so i figure it out is because loading the src need time and canvas create image before it fully load.
i need to make sure the json fully loaded on canvas first , so i found a fabric code call object:added , which can make sure object added in canvas , but it count object one by one , so if my json cotain 2 object it will create more image.
achievement
1. i need to make sure my json fully load or create in canvas before create image , is they any way to make sure json fully added to canvas?
Demo see my problem using object:added it load multiple image.
You should dump reviver and use just the callback function.
http://jsfiddle.net/v1nmtz02/2/
You will have some difficulties with fabricImages and objects that have a content that is async. That is not yet solved at library level.
function _callback() {
canvas.renderAll();
toImg();
}
function convertImgToBase64(number, outputFormat){
var tmpData = canvas.loadFromJSON(json[number], _callback);
}
Complete snippet:
var canvas = new fabric.Canvas('canvas');
var json2 = '{"objects":[{"type":"circle","originX":"center","originY":"center","left":300,"top":400,"width":200,"height":200,"fill":"rgb(166,111,213)","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":{"color":"#5b238A","blur":20,"offsetX":-20,"offsetY":-10},"visible":true,"clipTo":null,"radius":100},{"type":"rect","originX":"center","originY":"center","left":300,"top":500,"width":150,"height":150,"fill":"#fbb802","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":{"color":"rgba(94, 128, 191, 0.5)","blur":5,"offsetX":10,"offsetY":10},"visible":true,"clipTo":null,"rx":0,"ry":0,"x":0,"y":0}],"background":""}';
var json = [];
json.push(json2);
function makeallImage(){
for (var v = 0; v < json.length; v++){
convertImgToBase64(v, "jpg");
}
}
function _callback() {
canvas.renderAll();
toImg();
}
function convertImgToBase64(number, outputFormat){
var tmpData = canvas.loadFromJSON(json[number], _callback);
}
function toImg(outputFormat){
var s = document.getElementById("last_Image");
var url = canvas.toDataURL();
var newImg = document.createElement("img");
newImg.src = url;
newImg.width = 100;
newImg.height = 100;
s.appendChild(newImg);
}
<script src="http://fabricjs.com/lib/fabric.js"></script>
<canvas id='canvas' width="550" height="550" style="border:#000 1px solid;"></canvas>
<button onclick="makeallImage();">makepng</button>
<div id="last_Image" style="background:red"></div>