Add material to mesh from node server - node.js

While I understand many of you may not have messed around with OWF (Ozone Widge Framework), it's merely wigetized html pages that communicate through a subscription service on the server.
Simple example I'm working with: http://blog.thematicmapping.org/2013/10/textural-terrains-with-threejs.html
I can successfully add a texture via THREE.ImageUtils.loadTexture() while navigating to the html page in Google Chrome. However, when I use OWF in Google Chrome and point my widget to the html page, I can only get it to load the mesh. If I attempt to load the texture, it's completely black. Therefore, it has nothing to do with (chrome --allow-file-access-from-files). I have verified this happens for the few examples I've tried from threejs.org. Obviously, it has something to do with the OWF implementation, but I was under the impression that these frameworks inherited the properties of the browser it was being run in (I could be completely wrong)... therefore, I assumed it would work.
EDIT: I made the poor mistake of assuming it was the widgetized framework causing the trouble. I linked one of the widgets directly to the node website and could not successfully render the terrain material. Then, I tried accessing it through a node.js server with no success.
Here's the code if anyone can tell me why it's black....
<!doctype html>
<html lang="en">
<head>
<title>three.js - Jotunheimen</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body { margin: 0; overflow: hidden; }
</style>
</head>
<body>
<div id="webgl"></div>
<script src="jsANDcss/3D/three.min.js"></script>
<script src="jsANDcss/3D/TrackballControls.js"></script>
<script src="jsANDcss/3D/TerrainLoader.js"></script>
<script>
window.addEventListener( 'resize', onWindowResize, false );
var width = window.innerWidth,
height = window.innerHeight;
var scene = new THREE.Scene();
/*scene.add(new THREE.AmbientLight(0xeeeeee));*/
var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
camera.position.set(0, -30, 30);
var controls = new THREE.TrackballControls(camera);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
var material;
var texture;
var terrainLoader = new THREE.TerrainLoader();
terrainLoader.load('jsANDcss/3D/jotunheimen.bin', function(data) {
var geometry = new THREE.PlaneGeometry(60, 60, 199, 199);
for (var i = 0, l = geometry.vertices.length; i < l; i++) {
geometry.vertices[i].z = data[i] / 65535 * 5;
}
var texture = THREE.ImageUtils.loadTexture('jsANDcss/3D/jotunheimen-texture.jpg');
var material = new THREE.MeshPhongMaterial({
map: texture
/*wireframe: true*/
});
var plane = new THREE.Mesh(geometry, material);
material.needsUpdate = true;
scene.add(plane);
});
render();
document.getElementById('webgl').appendChild(renderer.domElement);
function render() {
controls.update();
requestAnimationFrame(render);
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
}
</script>
</body>
</html>

If you use MeshPhongMaterial, you need to add a light to the scene. If you do not want to add a light, then use MeshBasicMaterial.
Also, do not set material.needsUpdate = true;. The loader does that for you. Loading is asynchronous, and the needsUpdate flag needs to be set at the right time.
Consider adding the plane to the scene in the loader callback, instead.
Also, if you are modifying the vertices, you need to recompute some things:
geometry.computeCentroids();
geometry.computeFaceNormals();
geometry.computeVertexNormals(); // required if you want your terrain "smooth"
three.js r.62

Related

How to retrieve Vector Tiles from Mapbox with d3.js and convert to geojson?

I am trying to replicate the example from Mike Bostock: https://observablehq.com/#d3/mapbox-vector-tiles
Since the language of Observable is not native Javascript, I am unable to get the example running.
Especially, the following two functions I am unable to get to work:
VectorTile = (await require("https://bundle.run/#mapbox/vector-tile#1")).VectorTile
Protobuf = require("pbf#3/dist/pbf.js")
require() is not a Javascript command. So, how can I get these two libraries?
What I tried:
Insert the libraries via <script></script> tags
Loading with await:
let VectorTile = await fetch('https://bundle.run/#mapbox/vector-tile#1.3.1');
let Protobuf = await fetch('https://unpkg.com/pbf#3.0.5/dist/pbf.js');
I am not sure if require() comes from node.js. So I played around with node.js but did not find a working solution either.
So, my question is: How can I get the example from Mike Bostock to work? Or in more general manner: How should I load vector tiles from Mapbox that I can convert them to geojson format as Mike is it doing in this example?
Regarding your first question, in order to get Mike Bostock's example to work you can keep in mind considerations:
Promises are something that Observable takes care of automatically, while node.js or JavaScript in browser does not, so you should take care of them
Add all the necessary libraries, while keeping in mind that the way you call them might be different from how Mike does so. As, for example, by default you should use Pbf, not Protobuf if you use pbf library (And yes require() comes from node.js)
For #mapbox/vector-tile library notice that it exports 3 objects, while you need VectorTile function (in node.js you could just use require().VectorTile). You can see how I've done it below for JavaScript in html
Finally you will need to insert generated svg code into html in order to display it, this is also something that Observable does automatically
I can't really tell how you 'should' load vector tiles, as I don't have much expertise in this particular aria. However, below I converted Mike Bostock's example to javascript, so you can see how it works outside of Observable.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
Map:
<div id='map'></div>
</div>
<script src="https://d3js.org/d3-array.v2.min.js"></script>
<script src="https://d3js.org/d3-geo.v2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-tile#1"></script>
<script src="https://d3js.org/d3-dsv.v2.min.js"></script>
<script src="https://d3js.org/d3-fetch.v2.min.js"></script>
<script src="https://unpkg.com/pbf#3.0.5/dist/pbf.js"></script>
<script src="https://bundle.run/#mapbox/vector-tile#1.3.1"></script>
<script>let VectorTile = _mapbox_vectorTile.VectorTile</script>
<script>
height = 600;
width = 954;
API_KEY = 'cfNfEQR1Qkaz-6mvWl8cpw';// Sign up for an API key: https://www.nextzen.org
projection = d3.geoMercator()
.center([-122.4183, 37.7750])
.scale(Math.pow(2, 21) / (2 * Math.PI))
.translate([width / 2, height / 2]).precision(0);
path = d3.geoPath(projection)
tile = d3.tile()
.size([width, height])
.scale(projection.scale() * 2 * Math.PI)
.translate(projection([0, 0]));
function filter({features}, test) {
return {type: "FeatureCollection", features: features.filter(test)};
};
function geojson([x, y, z], layer, filter = () => true) {
if (!layer) return;
const features = [];
for (let i = 0; i < layer.length; ++i) {
const f = layer.feature(i).toGeoJSON(x, y, z);
if (filter.call(null, f, i, features)) features.push(f);
}
return {type: "FeatureCollection", features};
}
tiles_pr = Promise.all(tile().map(async d => {
d.layers = new VectorTile(new Pbf(await d3.buffer(`https://tile.nextzen.org/tilezen/vector/v1/256/all/${d[2]}/${d[0]}/${d[1]}.mvt?api_key=${API_KEY}`))).layers;
return d;
}))
tiles_pr.then(
function(tiles){
//console.log(tiles)
map = `<svg viewBox="0 0 ${width} ${height}" xmlns="http://www.w3.org/2000/svg">${tiles.map(d => `
<path fill="#eee" d="${path(geojson(d, d.layers.water, d => !d.properties.boundary))}"></path>
<path fill="none" stroke="#aaa" d="${path(geojson(d, d.layers.water, d => d.properties.boundary))}"></path>
<path fill="none" stroke="#000" stroke-width="0.75" d="${path(geojson(d, d.layers.roads))}"></path>
`)}
</svg>`
document.getElementById('map').innerHTML=map;
}
);
</script>
</body>
</html>

D3 Line graph is not rendering on IE8

We are using D3 library for creating line graph in a project. It is working as expected in modern browsers inlcuding mobile devices.
We are using Aight Library (https://github.com/shawnbot/aight) for IE8 compatibility but it is still not rendering the graph.
Any help or suggestion would be appreciated.
index.html :---
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<script src="jquery.min.js"></script>
<script src="aight.js"></script>
<!-- <script>aight.browser.ie8 = true;</script> -->
<script src="d3.v2.js"></script>
<script src="d3nvtooltip.js"></script>
<script src="d3legend.js"></script>
<script src="d3line.js"></script>
<script src="d3linewithlegend.js"></script>
<script src="graph.js"></script>
<script src="aight.d3.js"></script>
<link href="d3.css" rel="stylesheet" type="text/css">
<style>
#test1 {
margin: 0;
padding: 0;
overflow: none;
}
</style>
</head>
<body>
<div id="test1">
<svg></svg>
</div>
</body>
</html>
graph.js : ---
$(document).ready(function() {
var margin = {top: 30, right: 10, bottom: 50, left: 60},
chart = d3LineWithLegend()
.xAxis.label('xAxis')
.width(width(margin))
.height(height(margin))
.yAxis.label('yAxis');
var svg = d3.select('#test1 svg')
.datum(generateData())
svg.transition().duration(500)
.attr('width', width(margin))
.attr('height', height(margin))
.call(chart);
chart.dispatch.on('showTooltip', function(e) {
var offset = $('#test1').offset(), // { left: 0, top: 0 }
left = e.pos[0] + offset.left,
top = e.pos[1] + offset.top,
formatter = d3.format(".04f");
var content = '<h3>' + e.series.label + '</h3>' +
'<p>' +
'<span class="value">[' + e.point[0] + ', ' + formatter(e.point[1]) + ']</span>' +
'</p>';
nvtooltip.show([left, top], content);
});
chart.dispatch.on('hideTooltip', function(e) {
nvtooltip.cleanup();
});
$(window).resize(function() {
var margin = chart.margin();
chart
.width(width(margin))
.height(height(margin));
d3.select('#test1 svg')
.attr('width', width(margin))
.attr('height', height(margin))
.call(chart);
});
function width(margin) {
var w = 800 - 20;
return ( (w - margin.left - margin.right - 20) < 0 ) ? margin.left + margin.right + 2 : w;
}
function height(margin) {
var h = 500 - 20;
return ( h - margin.top - margin.bottom - 20 < 0 ) ? margin.top + margin.bottom + 2 : h;
}
//data
function generateData() {
var data1 = [[1,250000],[2,249318],[3,248634],[4,247948],[5,247260],[6,246569],[7,245876],[8,245181],[9,244483],[10,243783],[11,243081],[12,242376],[13,241669],[14,240960],[15,240248],[16,239534],[17,238817],[18,238098],[19,237377],[20,236653],[21,235927],[22,235199],[23,234468],[24,233734],[25,232998],[26,232260],[27,231519],[28,230776],[29,230031],[30,229282],[31,228532],[32,227778],[33,227023],[34,226265],[35,225504],[36,224741],[37,223975],[38,223206],[39,222435],[40,221662],[41,220886],[42,220107],[43,219326],[44,218542],[45,217756],[46,216967],[47,216175],[48,215380],[49,214583],[50,213784],[51,212981],[52,212176],[53,211369],[54,210558],[55,209745],[56,208929],[57,208111],[58,207290],[59,206466],[60,205639],[61,204809],[62,203977],[63,203142],[64,202304],[65,201464],[66,200620],[67,199774],[68,198925],[69,198073],[70,197219],[71,196361],[72,195501],[73,194637],[74,193771],[75,192902],[76,192030],[77,191155],[78,190278],[79,189397],[80,188513],[81,187627],[82,186737],[83,185845],[84,184949],[85,184051],[86,183149],[87,182245],[88,181337],[89,180427],[90,179513],[91,178597],[92,177677],[93,176754],[94,175829],[95,174900],[96,173968],[97,173033],[98,172095],[99,171153],[100,170209],[101,169261],[102,168310],[103,167357],[104,166399],[105,165439],[106,164476],[107,163509],[108,162539],[109,161566],[110,160590],[111,159610],[112,158627],[113,157641],[114,156651],[115,155659],[116,154662],[117,153663],[118,152660],[119,151654],[120,150645],[121,149632],[122,148616],[123,147596],[124,146573],[125,145547],[126,144517],[127,143484],[128,142447],[129,141407],[130,140363],[131,139316],[132,138266],[133,137212],[134,136154],[135,135093],[136,134028],[137,132960],[138,131889],[139,130813],[140,129734],[141,128652],[142,127566],[143,126476],[144,125383],[145,124286],[146,123185],[147,122081],[148,120973],[149,119861],[150,118745],[151,117626],[152,116503],[153,115377],[154,114246],[155,113112],[156,111974],[157,110833],[158,109687],[159,108538],[160,107385],[161,106228],[162,105067],[163,103902],[164,102734],[165,101561],[166,100385],[167,99204],[168,98020],[169,96832],[170,95640],[171,94443],[172,93243],[173,92039],[174,90831],[175,89619],[176,88403],[177,87182],[178,85958],[179,84730],[180,83497],[181,82260],[182,81020],[183,79775],[184,78526],[185,77273],[186,76015],[187,74754],[188,73488],[189,72218],[190,70944],[191,69665],[192,68382],[193,67095],[194,65804],[195,64509],[196,63209],[197,61904],[198,60596],[199,59283],[200,57965],[201,56644],[202,55318],[203,53987],[204,52652],[205,51313],[206,49969],[207,48620],[208,47267],[209,45910],[210,44548],[211,43182],[212,41811],[213,40435],[214,39055],[215,37670],[216,36281],[217,34887],[218,33488],[219,32085],[220,30677],[221,29264],[222,27847],[223,26424],[224,24998],[225,23566],[226,22130],[227,20688],[228,19242],[229,17792],[230,16336],[231,14875],[232,13410],[233,11940],[234,10465],[235,8985],[236,7500],[237,6010],[238,4515],[239,3015],[240,1510],[241,0]];
return [
{
data: data1,
label: "Label"
}
];
}
});
From the documentation of Aight:
Aight is a collection of shims and polyfills that get IE8 up to speed
with a bare minimum of HTML5 compatibility, providing all of the
interfaces necessary to do HTML-only DOM manipulation with d3.js (and
other libraries that rely on those interfaces)
Your graph is svg-based, so you're going to have to find another solution if you need it to render in IE8 and lower. One such possibility would be to shim the svg functionality with R2D3 (raphael.js for D3). That will be able to handle some cases by translating to VML (via raphaël).

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>

InfoWindow with google maps api

How can I display two Infowindow on my map.
in my code I can open only one InfoWindow, but I will display at same time twoo InfoWindow on my map what can I do. my code is:
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng( 38.736946, 35.310059), 6);
map.openInfoWindow(new GLatLng( 38.582526, 42.846680),
document.createTextNode("Van Gölü"));
}
}
The Google Maps API v2 native InfoWindow only supports one per map. The Google Maps API v3 removes that limitation.
Either use a custom InfoWindow or migrate your application to the Google Maps API v3.
As #duncan observed, that Google Maps API v2 has been officially deprecated as of May 19, 2010 and will not be supported after May 19, 2013. New development in that API is strongly discouraged.
this code is working :
<!DOCTYPE html>
<html>
<head>
<META http-equiv=content-type content=text/html;charset=x-mac-turkish>
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 100% }
</style>
<script src="js/jquery.js"></script>
<script type="text/javascript"
src="https://maps.googleapis.com/maps/api/js?key=mykey&sensor=false">
</script>
<script type="text/javascript">
var map;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(39.078908,35.244141),
zoom: 6,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),
mapOptions);
infoWindow = new google.maps.InfoWindow();
var windowLatLng = new google.maps.LatLng(38.668356,33.376465);
infoWindow.setOptions({
content: "Tuz Golu",
position: windowLatLng,
});
infoWindow.open(map);
infoWindow2 = new google.maps.InfoWindow();
var windowLatLng2 = new google.maps.LatLng(38.565348,42.868652);
infoWindow2.setOptions({
content: "Van Golu",
position: windowLatLng2,
});
infoWindow2.open(map);
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width:65%; height:40%"></div>
</body>
</html>

Pivotal CRM 5.7 SmartPortal size

Do anyone of You guys know if it is possible to change default size of SmartPortal based on url (webpage) size? Default it is 1/3 of screen width and 250px height.
Is it possible to change it to take whole screen width and other height?
Mayby I must create a SmartPortal plugin for that or manipulate webpage DOM?
Any advice will be helpfull :)
I've figured it out (thanks to ShankarSangoli).
I used jQuery to modify iframe height.
Whole dashboard is just a html table, so using some selectors I was able to change iframe height.
This is my code:
<script type="text/javascript">
$(document).ready(function () {
//SmartPortal name
var SPname = 'Name of SmartPortal';
//function usage
resizeSP(SPname, 400);
});
function resizeSP(SP, size) {
$("table.TitleText td.TitleText:contains(" + SP + ")", parent.document).closest('#title-bar').parent().next().find('#contentNode').children(":first").css("height", size);
}
</script>
But there are some limitations!!! The html page used by SmartPortal must be in the same domain as Pivotal (JavaScript security limitations) so I saved my document on local drive and used relative URL in SP properties.
If You want to use webpage outside domain just create a html document containing iframe with target URL and load it into Pivotal.
Like this:
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
//SmartPortal name
var SPname = 'SP name;
//usage
resizeSP(SPname, 400);
});
function resizeSP(SP, size) {
$("table.TitleText td.TitleText:contains(" + SP + ")", parent.document).closest('#title-bar').parent().next().find('#contentNode').children(":first").css("height", size);
}
</script>
<style type="text/css">
* {
margin: 0;
padding: 0;
overflow: auto;
height: 100%;
}
iframe {
display:block;
width:100%;
border:none;
}
</style>
</head>
<body>
<iframe src="http://www.yoursite.com"></iframe>
</body>
I hope that it will be helpful for anyone :)

Resources