1

问候专家和其他程序员......

我用 d3.js 做了一些实验,在这里找到了一个很好的动画模拟时钟示例:

http://www.google.de/url?sa=t&rct=j&q=d3%20analog%20clock&source=web&cd=1&cad=rja&ved=0CDIQFjAA&url=http%3A%2F%2Fwww.ericbullington.com%2Farticles%2F2012%2F10%2F27%2Fd3-oclock&ei=NNgIUuCqKomsOKmDgMAK&usg=AFQjCNGoI2g7XQIguM_6UM5V_6WzeJyPxA&bvm=bv.50500085,d.bGE

我把它改成了4个时钟,同时显示当地时间、伦敦、纽约和香港时间……

代码(片段)如下所示:

测试.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HEAD>
<META content="IE=10.000" http-equiv="X-UA-Compatible">
<META charset="utf-8">     
<META http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<META name="viewport" content="width=device-width, initial-scale=1">
<SCRIPT src="d3.v2.min.js"></SCRIPT>
<SCRIPT src="clock.js"></SCRIPT>
</HEAD>      
<BODY>
<DIV class="herechart"></DIV>
<DIV class="londonchart"></DIV>
<DIV class="newyorkchart"></DIV>
<DIV class="hongkongchart"></DIV>
<SCRIPT src="clock.js"></SCRIPT>
</BODY></HTML>

clock.js(修订):

(function() {
  var clockGroup, fields, formatHour, formatMinute, formatSecond, height, offSetX, offSetY, pi, render, scaleHours, scaleSecsMins, vis, width;
  formatSecond = d3.time.format("%S");
  formatMinute = d3.time.format("%M");
  formatHour = d3.time.format("%H");
  herefields = function() {
    var d, data, hour, minute, second;
    d = new Date();
    second = d.getSeconds();
    minute = d.getMinutes();
    hour = d.getHours() + minute / 60;
    return data = [
      { "unit": "seconds", "text": formatSecond(d), "numeric": second },
      { "unit": "minutes", "text": formatMinute(d), "numeric": minute },
      { "unit": "hours", "text": formatHour(d), "numeric": hour }
    ];
  };
  londonfields = function() {
  // fields creating in the same way as in herfields function
  };
  newyorkfields = function() {
  // you get the idea
  };
  hongkongfields ) = function {
  // i did it again
  };
  width = 82;
  height = 82;
  offSetX = 82;
  offSetY = 82;
  pi = Math.PI;
  scaleSecsMins = d3.scale.linear().domain([0, 59 + 59 / 60]).range([0, 2 * pi]);
  scaleHours = d3.scale.linear().domain([0, 11 + 59 / 60]).range([0, 2 * pi]);

  // creating local clock frame
  vis = d3.selectAll(".herechart").append("svg:svg").attr("width", width).attr("height", height);
  clockGroup = vis.append("svg:g").attr("transform", "translate(" + offSetX + "," + offSetY + ")");

  // creating London time clock frame
  londonvis = d3.selectAll(".londonchart").append("svg:svg").attr("width", width).attr("height", height);
  londonGroup = londonvis.append("svg:g").attr("transform", "translate(" + 260 + "," + -4 + ")");

  // omitting creation of the two other clock frames

  // ommitting creation of clock hands (using .append(...)) and texts alltogether - see web example

  // render function
  render = function(heredata, londondata, newyorkdata, hongkongdata) {
    var hourArc, minuteArc, secondArc;
    clockGroup.selectAll(".clockhand").remove();
    londonGroup.selectAll(".clockhand").remove();
    newyorkGroup.selectAll(".clockhand").remove();
    hongkongGroup.selectAll(".clockhand").remove();

    secondArc = d3.svg.arc().innerRadius(0).outerRadius(70).startAngle(function(d) { return scaleSecsMins(d.numeric); }).endAngle(function(d) { return scaleSecsMins(d.numeric); });
    minuteArc = d3.svg.arc().innerRadius(0).outerRadius(66).startAngle(function(d) { return scaleSecsMins(d.numeric); }).endAngle(function(d) { return scaleSecsMins(d.numeric); });
    hourArc = d3.svg.arc().innerRadius(0).outerRadius(50).startAngle(function(d) { return scaleHours(d.numeric % 12); }).endAngle(function(d) { return scaleHours(d.numeric % 12); });

    clockGroup.selectAll(".clockhand").data(heredata).enter().append("svg:path").attr("d", function(d) { if (d.unit === "seconds") { return secondArc(d); } else if (d.unit === "minutes") { return minuteArc(d); } else if (d.unit === "hours") { return hourArc(d); }
    }).attr("class", "clockhand").attr("stroke", "black").attr("stroke-width", function(d) { if (d.unit === "seconds") { return 1; } else if (d.unit === "minutes") { return 3; } else if (d.unit === "hours") { return 3; } }).attr("fill", "none");

    londonGroup.selectAll(".clockhand").data(londondata).enter().append("svg:path").attr("d", function(d) { if (d.unit === "seconds") { return secondArc(d); } else if (d.unit === "minutes") { return minuteArc(d); } else if (d.unit === "hours") { return hourArc(d); }
    }).attr("class", "clockhand").attr("stroke", "black").attr("stroke-width", function(d) { if (d.unit === "seconds") { return 1; } else if (d.unit === "minutes") { return 3; } else if (d.unit === "hours") { return 3; } }).attr("fill", "none");

    newyorkGroup.selectAll(".clockhand").data(newyorkdata).enter().append("svg:path").attr("d", function(d) { if (d.unit === "seconds") { return secondArc(d); } else if (d.unit === "minutes") { return minuteArc(d); } else if (d.unit === "hours") { return hourArc(d); }
    }).attr("class", "clockhand").attr("stroke", "black").attr("stroke-width", function(d) { if (d.unit === "seconds") { return 1; } else if (d.unit === "minutes") { return 3; } else if (d.unit === "hours") { return 3; } }).attr("fill", "none");

    hongkongGroup.selectAll(".clockhand").data(hongkongdata).enter().append("svg:path").attr("d", function(d) { if (d.unit === "seconds") { return secondArc(d); } else if (d.unit === "minutes") { return minuteArc(d); } else if (d.unit === "hours") { return hourArc(d); }
    }).attr("class", "clockhand").attr("stroke", "black").attr("stroke-width", function(d) { if (d.unit === "seconds") { return 1; } else if (d.unit === "minutes") { return 3; } else if (d.unit === "hours") { return 3; } }).attr("fill", "none");
  };
  // end of render function

  // periodically getting time fields and give them to render function
  setInterval(function() {
    var data;
    heredata = herefields();
    londondata = londonfields();
    newyorkdata = newyorkfields();
    hongkongdata = hongkongfields();
    return render(heredata, londondata, newyorkdata, hongkongdata);
  }, 1000); }).call(this);

该代码对我来说很好用。

但我很想将它包含在我的一个 three.js 项目中,我在一个投影中使用两个具有两个不同渲染器(一个画布,一个 css3d 渲染器)的场景。我在那里做了很多飞行和旋转...... :-)

由于 D3 对象是 DIV,我想我可以创建 CSS3D 渲染的对象并将它们(TWEENING 和改变位置)与其他对象一起飞行。

有没有办法做到这一点?以及如何做到这一点。

下面,我展示了我在我的 three.js 项目中使用的一些代码,其中有一个 init() 函数,它创建 DIV 和场景、渲染器和投影......我在设计粒子和 DIV 以及很多在为它们设置动画的同时更改这些元素的东西......下面的代码效果很好(不是片段,而是完整的代码)。但是我该如何组合它们呢?

<body onload="connameinit();">
    <script src="build/three.min.js"></script>
    <script src="js/renderers/CSS3DRenderer.js"></script>
    <script src="js/libs/tween.min.js"></script>
    <script>
        function init() {
            container = document.createElement( 'div' );
            document.body.appendChild( container );
            camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 3000 );
            camera.position.z = 1000;
            scene = new THREE.Scene();
            var program = function ( context ) {

                myindex++;
                context.beginPath();
                context.rect( 3, 12, 7, 1);
                context.drawImage(backgroundImage01, 0, 0);

                context.closePath();
                context.fill();
            }
            group = new THREE.Object3D();
            scene.add( group );
            for ( var i = 0; i < 400; i++ ) {
                particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( { map: new THREE.Texture( generateSprite() ), color: Math.random() * 0x808008 + 0x808080, program: program } ) );
                particle.position.x = Math.random() * 6000 - 3000;
                particle.position.y = Math.random() * 6000 - 3000;
                particle.position.z = Math.random() * 6000 - 5500;
                particle.scale.x = particle.scale.y = Math.random() * 3 + 2;
                initParticle( particle, i * 10 );
                group.add( particle );
                myparticles.push( particle );
            }
            renderer = new THREE.CanvasRenderer();
            renderer.setClearColor(0x000000, 1);
            renderer.setSize( window.innerWidth, window.innerHeight );
            container.appendChild( renderer.domElement );
            // creating the CSS3D rendered object
            scene2 = new THREE.Scene();
            var element = document.createElement( 'div' );
            element.className = 'element';
            element.style.width = Math.floor(window.innerWidth / window.innerHeight * 1400) + 'px';
            element.style.height = '1400px';
            element.style.backgroundColor = 'rgba(0,127,127,' + ( Math.random() * 0.5 + 0.25 ) + ')';
            var profile = document.createElement( 'div' );
            profile.className = 'profile';
            profile.textContent = "";
            element.appendChild( profile );
            myimgdiv = new THREE.CSS3DObject( element );
            myimgdiv.position.x = 0;
            myimgdiv.position.y = 0;
            myimgdiv.position.z = 0;
            scene2.add( myimgdiv );
            renderer2 = new THREE.CSS3DRenderer();
            renderer2.setSize( window.innerWidth, window.innerHeight );
            renderer2.domElement.style.position = 'absolute';
            renderer2.domElement.style.top = 0;
            document.body.appendChild( renderer2.domElement );
        }
        function animate() {
            requestAnimationFrame( animate );
            render();
        }
        function render() {
            TWEEN.update();
            camera.lookAt( scene.position );
            mypindex = mypindex + mypmul;
            if (mypindex > 500) {
                mymulti = - mymulti;
                mypmul = -1;
            }
            if (mypindex < -500) {
                mymulti = - mymulti;
                mypmul = 1;
            }
            group.rotation.x += mymulti * 0.0003;
            group.rotation.y += mymulti * 0.0006;
            myimgdiv.scale.x += mymulti * 0.0001;
            myimgdiv.scale.y += mymulti * 0.0001;
            renderer.render( scene, camera );
            renderer2.render( scene2, camera );
        }
        function mydivtransform( targets, duration ) {
                var object = myimgdiv;
                var target = targets[ 0 ];
                new TWEEN.Tween( object.position )
                    .to( { x: target.position.x, y: target.position.y, z: object.position.z }, duration )
                    .easing( TWEEN.Easing.Exponential.InOut )
                    .start();
        }
    </script>
</body>
</html>

我可以在 init() 循环中创建时钟 DIV,而不是将代码放在文档正文中吗?然后我会以某种方式拆分clock.js代码并将其一部分放入init()循环中,但是有人可以帮我吗?不过,我认为最好的方法是使用第三个渲染器(CSS3D),使用相同的投影仪来创建第三个场景。但是如何从 D3 对象创建 Three.js 混搭?当这些 Three.js 对象被移动或 TWEENed 时,我如何确保时钟指针的动画继续?

预先感谢您的所有帮助!

奥利弗

4

0 回答 0