<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Axis</title> <link rel="stylesheet" type="text/css" href="3DGraph.css"/> <style src="3DGraph.css"></style> </head> <body> <script type="text/javascript" src="three.min.js"></script> <script type="text/javascript" src="Projector.js"></script> <script type="text/javascript" src="CanvasRenderer.js"></script> <script type="text/javascript" src="https://d3js.org/d3.v3.min.js"></script> <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script> <script type="text/javascript" src="3DGraph.js" charset="utf-8"></script> <script> var stockValues = [ { market : "Nikkei 225", color : 'cyan', dataset : [ {"date":new Date('Sep 14,2015').getTime(),"value":18070}, {"date":new Date('Sep 7,2015').getTime(),"value":18264}, {"date":new Date('Aug 31,2015').getTime(),"value":17792}, {"date":new Date('Aug 24,2015').getTime(),"value":19136}, {"date":new Date('Aug 17,2015').getTime(),"value":19435}, {"date":new Date('Aug 10,2015').getTime(),"value":20519}, {"date":new Date('Aug 3,2015').getTime(),"value":20724}, {"date":new Date('Jul 27,2015').getTime(),"value":20585}, {"date":new Date('Jul 20,2015').getTime(),"value":20544}, {"date":new Date('Jul 13,2015').getTime(),"value":20650}, {"date":new Date('Jul 6,2015').getTime(),"value":19779}, {"date":new Date('Jun 29,2015').getTime(),"value":20539}, {"date":new Date('Jun 23,2015').getTime(),"value":20706}, {"date":new Date('Jun 15,2015').getTime(),"value":20174}, {"date":new Date('Jun 8,2015').getTime(),"value":20407}, {"date":new Date('Jun 1,2015').getTime(),"value":20460}, ]}, { market : "N.Y. DOW", color : 'yellow', dataset : [ {"date":new Date('Sep 14,2015').getTime(),"value":16384}, {"date":new Date('Sep 7,2015').getTime(),"value":16433}, {"date":new Date('Aug 31,2015').getTime(),"value":16102}, {"date":new Date('Aug 24,2015').getTime(),"value":16643}, {"date":new Date('Aug 17,2015').getTime(),"value":16459}, {"date":new Date('Aug 10,2015').getTime(),"value":17477}, {"date":new Date('Aug 3,2015').getTime(),"value":17373}, {"date":new Date('Jul 27,2015').getTime(),"value":17689}, {"date":new Date('Jul 20,2015').getTime(),"value":17568}, {"date":new Date('Jul 13,2015').getTime(),"value":18086}, {"date":new Date('Jul 6,2015').getTime(),"value":17760}, {"date":new Date('Jun 29,2015').getTime(),"value":17730}, {"date":new Date('Jun 23,2015').getTime(),"value":17946}, {"date":new Date('Jun 15,2015').getTime(),"value":18015}, {"date":new Date('Jun 8,2015').getTime(),"value":17898}, {"date":new Date('Jun 1,2015').getTime(),"value":17849}, ]}, { market : "Shanghai", color : 'red', dataset : [ {"date":new Date('Sep 14,2015').getTime(),"value":3097}, {"date":new Date('Sep 7,2015').getTime(),"value":3200}, {"date":new Date('Aug 31,2015').getTime(),"value":3160}, {"date":new Date('Aug 24,2015').getTime(),"value":3232}, {"date":new Date('Aug 17,2015').getTime(),"value":3507}, {"date":new Date('Aug 10,2015').getTime(),"value":3965}, {"date":new Date('Aug 3,2015').getTime(),"value":3744}, {"date":new Date('Jul 27,2015').getTime(),"value":3663}, {"date":new Date('Jul 20,2015').getTime(),"value":4070}, {"date":new Date('Jul 13,2015').getTime(),"value":3957}, {"date":new Date('Jul 6,2015').getTime(),"value":3877}, {"date":new Date('Jun 29,2015').getTime(),"value":3686}, {"date":new Date('Jun 23,2015').getTime(),"value":4192}, {"date":new Date('Jun 15,2015').getTime(),"value":4478}, {"date":new Date('Jun 8,2015').getTime(),"value":5166}, {"date":new Date('Jun 1,2015').getTime(),"value":5023}, ]} ]; // mouse var mouseX = 0; var mouseY = 0; var windowX = window.innerWidth; var windowY = window.innerHeight; var windowHalfX = windowX / 2; var windowHalfY = windowY / 2; $(document).on('mousemove', function(event) { mouseX = (event.clientX - windowHalfX) / windowX; mouseY = (event.clientY - windowHalfY) / windowY; }); // (1) Scene var scene = new THREE.Scene(); // (2) Light var ambient = new THREE.AmbientLight( 0x404040 ); scene.add( ambient ); var spotlight = new THREE.SpotLight( 0xffffff, 3, 0, Math.PI / 2 ); spotlight.target.position.set(0,0,0); spotlight.position.z = 100; scene.add(spotlight); // (3) Camera //var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 ); var camera = new THREE.OrthographicCamera( window.innerWidth/-3,window.innerWidth/3,window.innerHeight/3,window.innerHeight/-3,0.1 , 2000 ); camera.position.x = 1000.0 * Math.sin(2.0 * Math.PI * mouseX); camera.position.y = 2000.0 * mouseY; camera.position.z = 1000.0 * Math.cos(2.0 * Math.PI * mouseX); camera.lookAt(new THREE.Vector3(-1.0 * camera.position.x ,-1.0 * camera.position.y,-1.0 * camera.position.z)); // (4) Plane var offset = 0; for (stockValue of stockValues) { // テクスチャを作成 var svg = plot(stockValue.market, stockValue.dataset, 512, 128, 'linear', stockValue.color); var canvas = svg2canvas(svg); /* var texture = new THREE.Texture(canvas); texture.needsUpdate = true; */ var texture = THREE.ImageUtils.loadTexture(canvas2png(canvas)); // 質感 var planeMaterial = new THREE.MeshBasicMaterial({ map : texture, overdraw: true, side:THREE.DoubleSide, transparent: true, color: 0xffffff, }); var plane = new THREE.Mesh(new THREE.PlaneGeometry( 512, 128 ), planeMaterial); plane.position.y = 64; plane.position.z = offset; scene.add(plane); offset -= 40; } /* // xyz軸 (補助線) var axes = new THREE.AxisHelper(1000); scene.add( axes ); */ //GridHelper(大きさ, 1マスの大きさ) var grid = new THREE.GridHelper(300, 10); scene.add(grid); // (5) WebGL Renderer //renderer = new THREE.WebGLRenderer(); // webgl is good but we want to run in webview component of javafx. renderer = new THREE.CanvasRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.setClearColor(0x000000); renderer.clear(true); $('body').append( renderer.domElement ); // (6) Animation function animation() { camera.position.x = 1000.0 * Math.sin(2.0 * Math.PI * mouseX); camera.position.y = 2000.0 * mouseY; camera.position.z = 1000.0 * Math.cos(2.0 * Math.PI * mouseX); camera.lookAt(new THREE.Vector3(-1.0 * camera.position.x ,-1.0 * camera.position.y,-1.0 * camera.position.z)); spotlight.position.x = camera.position.x; spotlight.position.y = camera.position.y; spotlight.position.z = camera.position.z; renderer.render( scene, camera ); requestAnimationFrame(animation) } animation(); </script> </body> </html>
// to create SVG, HTML and XUL elements needs namespace var dom = document.createElementNS("http://www.w3.org/2000/svg", "svg"); var svg = d3.select(dom).attr({width: w, height: h}).style("padding","5px");
// append css to axis // we need append style attributes on the svg-tags, because canvas renderer don't refer css svg.selectAll('.axis').selectAll('text').attr({ 'font-family': 'sans-serif', 'font-size': '8px', 'stroke': color, }); svg.selectAll('.axis').selectAll('path').attr({ 'fill': 'none', 'stroke': color, 'shape-rendering': 'crispEdges' }); svg.selectAll('.axis').selectAll('line').attr({ 'fill': 'none', 'stroke': color, 'shape-rendering': 'crispEdges' });
function svg2canvas(svg) { var $svg = $(svg); var canvas = document.createElement('canvas'); canvas.width = $svg.attr('width'); canvas.height = $svg.attr('height'); context = canvas.getContext("2d"); var image = new Image(); image.src = "data:image/svg+xml;charset=utf-8;base64," + btoa(unescape(encodeURIComponent((new XMLSerializer()).serializeToString(svg)))); context.drawImage(image, 0, 0); return canvas; }
SVG と同じ縦横の Canvas を作って、その (0,0) から DataURL 化された SVG を流し込む
function canvas2png(canvas) { return canvas.toDataURL(); }
toDataURL() の引き数に 'image/png' を指定してもよい。W3C の規格上、フォーマット未指定時は PNG を返す。
var offset = 0; for (stockValue of stockValues) { // テクスチャを作成 var svg = plot(stockValue.market, stockValue.dataset, 512, 128, 'linear', stockValue.color); var canvas = svg2canvas(svg); var texture = THREE.ImageUtils.loadTexture(canvas2png(canvas)); // 質感 var planeMaterial = new THREE.MeshBasicMaterial({ map : texture, overdraw: true, side:THREE.DoubleSide, transparent: true, color: 0xffffff, }); var plane = new THREE.Mesh(new THREE.PlaneGeometry( 512, 128 ), planeMaterial); plane.position.y = 64; plane.position.z = offset; scene.add(plane); offset -= 40; }