后端使用usign bottle webframework,前端使用d3图形。
我的server.py内容如下

from bottle import get,template,run,route,Bottle,static_file
from bottle.ext.websocket import GeventWebSocketServer
from bottle.ext.websocket import websocket
import random
import time
users = set()
@get('/')
def mainIndex():
    return template('problemToAskFromStackoverflow')

import time
@get('/websocket', apply=[websocket])
def chat(ws):
      users.add(ws)
      startTime = 0#time.time()
      while True:
          msg = ws.receive()
          #print "msg ",msg
          if msg is not None:
               for u in users:
                   speed = random.randrange(0,1000)
                   weight = random.randrange(0,50)
                   #elapsedTime = time.time() - startTime
                   startTime += 1
                   print "time:",startTime
                  obj = '{"speed":'+str(speed) +    ',"weight":'+str(weight)+',"time":'+str(startTime)+'}'
                  u.send(str(speed))
                  #u.send(str(random.randrange(0,1000)))
            else:
                 print "msg is NONe is guesse"
                 break
           time.sleep(1)
   users.remove(ws)

run(host='localhost',port=8004,server=GeventWebSocketServer)


和问题toAskFromStackoverflow.html的内容如下



<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<meta charset="utf-8">
<style>

svg {
  font: 10px sans-serif;
}

.line {
  fill: none;
  stroke: #000;
  stroke-width: 1.5px;
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

</style>
<body>
    <form id="startBtn">
            <input type="submit" value="Start Real" />
    </form>
<div id = "graph1"></div>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
        var margin = {top:5, right: 10, bottom: 10, left: 70},
            width = 1200 - margin.left - margin.right,
            height = 250 - margin.top - margin.bottom;

        var data1;
        var x,y1,xAxis1,yAxis1,update;
        var duration = 1000;
	var moveDuration = 1000;
        // Parse the date / time
                var totalSeconds = 60;
                var n = 10;//totalSeconds;
		var limit = n;
                duration = 1000;
                x = d3.time.scale()
                           .domain([0, ((n - 1) * duration)])
                           .range([0, width]);
        var valueline1 = d3.svg.line()
                .x(function(d,i) { return x(i*duration); })
                .y(function(d,i) { return y1(d); })
                .interpolate("monotone");

   // Set the ranges
                data1 = [0];


                y1 = d3.scale.linear().range([height, 0])
                                        .domain([0,1000]);
               xAxis1 =d3.svg.axis().scale(x)
                                .orient("bottom")
                                .ticks(d3.time.seconds, 1.0)
                                .tickFormat(d3.time.format('%M:%S'))
                                .innerTickSize(-height);
                yAxis1 = d3.svg.axis().scale(y1)
                        .innerTickSize(-width)
                        .outerTickSize(0)
                        .tickPadding(10)
                        .orient("left").ticks(10);
 		var svg = d3.select("#graph1")
                        .append("svg")
                        .attr("width", width + margin.left + margin.right)
                        .attr("height", height + margin.top + margin.bottom)
                        .append("g")
                        .attr("transform","translate(" + margin.left + "," + margin.top + ")");
               svg.append("defs").append("clipPath")
		    .attr("id", "clip")
		    .append("rect")
		    .attr("width", width)
		    .attr("height", height);

		var xAxisLine= svg.append("g")                     // Add the X Axis
                        .attr("class", "x axis")
                        .attr("transform", "translate("+width+"," + height + ")")
                        .call(xAxis1);

		svg.append("g")                     // Add the Y Axis
                        .attr("class", "y axis")
                        .call(yAxis1);

                var path = svg.append("g")
                                .attr("clip-path","url(#clip)")
                                .append("path")
                                .data(data1)
                                .attr("class", "line")
                                .attr("transform", "translate(" + (width )+")")
				.attr("d",valueline1(data1))
				;          // Add the valueline path.


	var random = d3.random.normal(0, 50);
	var  i = 0;
	var shifter = 0;
       function update(val){
                var svg1 = d3.select("#graph1");
                i = i + 1;
                shifter = 0;
                var val = JSON.parse(val);
               	data1.push(val);

                if(i >= limit){
                        shifter = x(-duration);
                        var x_axis_scale = d3.time.scale()
                                                .domain([(i+1-limit)*duration,((n-1+(i+1-limit))*duration)])
                                                .range([0,width]);

                        svg1.select(".x.axis")
				.attr("transition",null)
                                .transition()
                                .duration(moveDuration)
                                .ease("linear")
					.call(d3.svg.axis().scale(x_axis_scale)
					.orient("bottom")
                                	.ticks(d3.time.seconds, 1.0)
                                	.tickFormat(d3.time.format('%M:%S'))
                                	.innerTickSize(-height)
                                        //.orient("bottom")
					//.ticks(d3.time.seconds,1.0)
					//.tickFormat(d3.time.format('%M:%S'))
					//.innerTickSize(-height)
				);

                                //.attr("width",width)
				path//.attr("transform",null)
                                .attr("d", valueline1(data1))
				.attr("transform",null)
				.transition()
                                .duration(moveDuration)
                                .ease("linear")
                                .attr("transform","translate("+(shifter)+")")
                                //.transition()
                                //.duration(moveDuration)
                                //.ease("linear")
                                ;//.attr("transform","translate("+(shifter-x(-duration))+")");

                        data1.shift();
                        // Make the changes
                }
                else{
                        shifter = width - x(i*duration);
                        svg1.select(".x.axis")

                                .transition()
                                .duration(moveDuration)
                                .ease("linear")
                                .attr("transform","translate("+(shifter)+","+(height)+")");

		//	svg1.select(".line")   // change the line
                  path              .attr("d", valueline1(data1))
                                .transition()
                                .duration(moveDuration)
                                .ease("linear")
                                .attr("transform","translate("+(shifter)+")")
                                ;//.attr("transform","translate("+(shifter)+")");

                        // Make the changes
                        }

        }
var  ws = new WebSocket('ws://127.0.0.1:8004/websocket')
ws.onopen = function(evt) {
}

ws.onmessage = function(evt) {
	//alert(evt.data)
	update(evt.data);
	ws.send("arrived");
}
$('#startBtn').submit(function() {
	ws.send("Pressed");
});

</script>





当我在终端上运行server.py并在i超出限制后打开localhost:8004时,经过10秒后,路径的流动不如超出限制前那么平滑。我搜索的解决方案不知道是什么问题?我认为这可能是在现有过渡的基础上增加新的过渡。但是事实并非如此,即使我在updtae功能的其他部分禁用了所有与转换相关的行,但是如果更新功能的一部分仍未包含转换。如果您能帮助我解决这个问题,我将非常高兴。

最佳答案

这很奇怪,您的代码应该可以工作。就像d3没有拿起transition.attr并应用它。最好的选择是设置自己的插值器:

var startTrans = 'translate(0,0)';
var endTrans = 'translate(' + (-x(duration)) + ',0)';
var transInterp = d3.interpolateString(startTrans , endTrans);
...
path
  .attr("d", valueline1(data1))
  .attr("transform", null)
  .transition()
  .duration(moveDuration)
  .ease("linear")
  .attrTween('transform', function (d) {
    return transInterp;
  });


完整的工作代码:



<!DOCTYPE html>
<meta charset="utf-8">
<style>
  svg {
    font: 10px sans-serif;
  }

  .line {
    fill: none;
    stroke: #000;
    stroke-width: 1.5px;
  }

  .axis path,
  .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
  }
</style>

<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
  <div id="graph1"></div>
  <script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
  <script>

    var margin = {
        top: 5,
        right: 10,
        bottom: 10,
        left: 70
      },
      width = 600 - margin.left - margin.right,
      height = 250 - margin.top - margin.bottom;

    var data1;
    var x, y1, xAxis1, yAxis1, update;
    var duration = 1000;
    var moveDuration = 1000;
    // Parse the date / time
    var totalSeconds = 60;
    var n = 10; //totalSeconds;
    var limit = n;
    duration = 1000;
    x = d3.time.scale()
      .domain([0, ((n - 1) * duration)])
      .range([0, width]);
    var valueline1 = d3.svg.line()
      .x(function(d, i) {
        return x(i * duration);
      })
      .y(function(d, i) {
        return y1(d);
      })
      .interpolate("monotone");

    // Set the ranges
    data1 = [0];


    y1 = d3.scale.linear().range([height, 0])
      .domain([0, 1000]);
    xAxis1 = d3.svg.axis().scale(x)
      .orient("bottom")
      .ticks(d3.time.seconds, 1.0)
      .tickFormat(d3.time.format('%M:%S'))
      .innerTickSize(-height);
    yAxis1 = d3.svg.axis().scale(y1)
      .innerTickSize(-width)
      .outerTickSize(0)
      .tickPadding(10)
      .orient("left").ticks(10);
    var svg = d3.select("#graph1")
      .append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    svg.append("defs").append("clipPath")
      .attr("id", "clip")
      .append("rect")
      .attr("width", width)
      .attr("height", height);

    var xAxisLine = svg.append("g") // Add the X Axis
      .attr("class", "x axis")
      .attr("transform", "translate(" + width + "," + height + ")")
      .call(xAxis1);

    svg.append("g") // Add the Y Axis
      .attr("class", "y axis")
      .call(yAxis1);

    var path = svg.append("g")
      .attr("clip-path", "url(#clip)")
      .append("path")
      .data(data1)
      .attr("class", "line")
      .attr("transform", "translate(" + (width) + ")")
      .attr("d", valueline1(data1)); // Add the valueline path.


    var random = d3.random.normal(0, 50);
    var i = 0;
    var shifter = 0;
    var startTrans = 'translate(0,0)';
    var endTrans = 'translate(' + (-x(duration)) + ',0)';
    var transInterp = d3.interpolateString(startTrans, endTrans);

    function update(val) {
      var svg1 = d3.select("#graph1");
      i = i + 1;
      shifter = 0;
      var val = JSON.parse(val);
      data1.push(val);

      if (i >= limit) {
        shifter = x(-duration);
        var x_axis_scale = d3.time.scale()
          .domain([(i + 1 - limit) * duration, ((n - 1 + (i + 1 - limit)) * duration)])
          .range([0, width]);

        svg1.select(".x.axis")
          .attr("transition", null)
          .transition()
          .duration(moveDuration)
          .ease("linear")
          .call(d3.svg.axis().scale(x_axis_scale)
            .orient("bottom")
            .ticks(d3.time.seconds, 1.0)
            .tickFormat(d3.time.format('%M:%S'))
            .innerTickSize(-height)
            //.orient("bottom")
            //.ticks(d3.time.seconds,1.0)
            //.tickFormat(d3.time.format('%M:%S'))
            //.innerTickSize(-height)
          );


        path
          .attr("d", valueline1(data1))
          .attr("transform", null)
          .transition()
          .duration(moveDuration)
          .ease("linear")
          .attrTween('transform', function (d) {
            return transInterp;
          });

        data1.shift();
        // Make the changes
      } else {
        shifter = width - x(i * duration);
        svg1.select(".x.axis")

        .transition()
          .duration(moveDuration)
          .ease("linear")
          .attr("transform", "translate(" + (shifter) + "," + (height) + ")");

        //	svg1.select(".line")   // change the line
        path.attr("d", valueline1(data1))
          .transition()
          .duration(moveDuration)
          .ease("linear")
          .attr("transform", "translate(" + (shifter) + ")"); //.attr("transform","translate("+(shifter)+")");

        // Make the changes
      }

    }

    setInterval(function() {
      update(Math.random() * 1000);
    }, 1000);
  </script>

09-20 12:52