Существует ли способ получить значение свойства использования объекта класс PropertyPath?

Я решил проблему. Проблема возникла из-за смешения API из d3.v3 и d3.v4. Я перенес весь мой код в реализацию d3.v3. Размещаем этот код здесь, так что если кто-то захочет увидеть реализацию диаграммы во всплывающей подсказке другой диаграммы.

Вот полный код:

<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8' />
  <title>Question 5 </title>
  <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
  <style>
    body {
      font-family: "Arial", sans-serif;
    }
    
    .bar {
      fill: gray;
      /*#5f89ad;*/
    }
    
    rect:hover {
      fill: #1E90FF;
    }
    
    .axis {
      font-size: 13px;
    }
    
    .axis path,
    .axis line {
      fill: none;
      /*display: none;*/
    }
    
    .label {
      font-size: 13px;
      font-weight: bold;
    }
    
    text {
      font-weight: bold;
    }
    
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 2px;
    }
    
    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
    /*.d3-tip {
  line-height: 1;
  padding: 6px;
  background: wheat;
  border-radius: 4px solid black;
  font-size: 12px;
}*/
  </style>

</head>

<body>

  <div id="graphic"></div>

  <script>
    var data = [{
        country: 'Bangladesh',
        population_2012: 105905297,
        growth: {
          year_2013: 42488,
          year_2014: 934,
          year_2015: 52633,
          year_2016: 112822,
          year_2017: 160792
        }
      },
      {
        country: 'Ethopia',
        population_2012: 75656319,
        growth: {
          year_2013: 1606010,
          year_2014: 1606705,
          year_2015: 1600666,
          year_2016: 1590077,
          year_2017: 1580805
        }
      },
      {
        country: 'Kenya',
        population_2012: 33007327,
        growth: {
          year_2013: 705153,
          year_2014: 703994,
          year_2015: 699906,
          year_2016: 694295,
          year_2017: 687910
        }
      },
      {
        country: 'Afghanistan',
        population_2012: 23280573,
        growth: {
          year_2013: 717151,
          year_2014: 706082,
          year_2015: 665025,
          year_2016: 616262,
          year_2017: 573643
        }
      },
      {
        country: 'Morocco',
        population_2012: 13619520,
        growth: {
          year_2013: 11862,
          year_2014: 7997,
          year_2015: 391,
          year_2016: -8820,
          year_2017: -17029
        }
      }
    ];

    data_growth = [];

    for (i = 0; i < data.length; i++) {
      data[i]["total_population"] = data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"] + data[i].growth["year_2016"] + data[i].growth["year_2017"];

      data[i]["growth_data"] = [{
          "year": 2013,
          "growth": (data[i].growth["year_2013"] / (data[i]["population_2012"])) * 100
        },
        {
          "year": 2014,
          "growth": (data[i].growth["year_2014"] / (data[i]["population_2012"] + data[i].growth["year_2013"])) * 100
        },
        {
          "year": 2015,
          "growth": (data[i].growth["year_2015"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"])) * 100
        },
        {
          "year": 2016,
          "growth": (data[i].growth["year_2016"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"])) * 100
        },
        {
          "year": 2017,
          "growth": (data[i].growth["year_2017"] / (data[i]["population_2012"] + data[i].growth["year_2013"] + data[i].growth["year_2014"] + data[i].growth["year_2015"] + data[i].growth["year_2016"])) * 100
        }
      ];
    }

    //console.log(data);

    //sort bars based on population_2012
    data = data.sort(function(a, b) {
      return d3.ascending(a.population_2012, b.population_2012);
    })

    //set up svg using margin conventions - we'll need plenty of room on the left for labels
    var margin = {
      top: 15,
      right: 25,
      bottom: 15,
      left: 160
    };

    var width = 960 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;

    var svg = d3.select("#graphic").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 + ")");

    var tool_tip = d3.tip()
      .attr("class", "d3-tip")
      .offset([20, 670])
      .html("<p>Year-wise growth in population for the country:</p><div id='tipDiv' style='border: 1px solid gray;'></div>");

    svg.call(tool_tip);

    var x = d3.scale.linear()
      .range([0, width])
      .domain([0, d3.max(data, function(d) {
        return d.population_2012;
      })]);

    var y = d3.scale.ordinal()
      .rangeRoundBands([height, 0], .1)
      .domain(data.map(function(d) {
        return d.country;
      }));

    //make y axis to show bar countrys
    var yAxis = d3.svg.axis()
      .scale(y)
      //no tick marks
      .tickSize(0)
      .orient("left");

    var gy = svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)

    var bars = svg.selectAll(".bar")
      .data(data)
      .enter()
      .append("g")

    //append rects
    bars.append("rect")
      .attr("class", "bar")
      .attr("y", function(d) {
        return y(d.country);
      })
      .attr("height", y.rangeBand())
      .attr("x", 0)
      .attr("width", function(d) {
        return x(d.total_population);
      })
      .attr('fill', 'gray')
      .on('mouseover', function(d) {

        //console.log("d:==>", d);
        tool_tip.show();
        var points_raw = d3.range(10).map(function() {
          return {
            year: Math.random() * 100,
            growth: Math.random() * 100
          }
        });
        //console.log("points-raw:==>", points_raw)
        // sort by x, descending
        //points = points_raw.sort(function(a, b) { return d3.descending(a.year, b.year); });
        //points = points_raw
        points = d["growth_data"];

        // set up canvas
        var margin = {
            top: 20,
            right: 30,
            bottom: 40,
            left: 60
          },
          width = 420 - margin.left - margin.right,
          height = 320 - margin.top - margin.bottom;

        var x = d3.scale.linear()
          .range([0, width])
          .domain(points.map(function(d) {
            return d.year;
          }));;

        var y = d3.scale.linear()
          .range([height, 0])
          .domain([0, d3.max(points, function(d) {
            return d.growth;
          })]);

        var x_axis = d3.svg.axis()
          .scale(x)
          .ticks(5)
          .orient('bottom');

        var y_axis = d3.svg.axis()
          .scale(y)
          .orient('left');

        // define line function
        var line = d3.svg.line()
          .x(function(d) {
            return x(d.year);
          })
          .y(function(d) {
            return y(d.growth);
          })
        /*.interpolate('basis')*/
        ;

        /*points.forEach(function(d) {
    d.growth = +d.growth;
  });*/

        // add svg element
        var svg = d3.select('#tipDiv')
          .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 + ")");

        // determine domain ranges for x/y
        x.domain(d3.extent(points, function(d) {
          return d.year;
        }));
        /*x.domain(points.map(function (d) {
                return d["year"];
            }));
	*/
        y.domain(d3.extent(points, function(d) {
          return d.growth;
        }));

        // add labeled x-axis
        svg.append('g')
          .attr('class', 'x axis')
          .attr("transform", "translate(0," + height + ")")
          .call(x_axis)
          .append("text")
          .attr("x", width - 6)
          .attr("dy", "3em")
          /*.style("text-anchor", "end")*/
          .text("Year");

        // add labeled y-axis
        svg.append('g')
          .attr('class', 'y axis')
          .call(y_axis)
          .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 0)
          .attr("dy", "-3.71em")
          .style("text-anchor", "end")
          .text("Pct %");

        // draw line
        svg.append('path')
          .datum(points)
          .attr('class', 'line')
          .attr('d', line);

      })
      .on('mouseout', tool_tip.hide);

    //add a population_2012 label to the right of each bar
    bars.append("text")
      .attr("class", "label")
      //y position of the label is halfway down the bar
      .attr("y", function(d) {
        return y(d.country) + y.rangeBand() / 2 + 4;
      })
      //x position is 3 pixels to the right of the bar
      .attr("x", 15
        /*(function (d) {
                        return x(d.population_2012) + 3;
                    }*/
      )
      .text(function(d) {
        return d.total_population.toLocaleString();
      });
  </script>

</body>

</html>

7
задан Andy 18 May 2009 в 11:01
поделиться

2 ответа

Reusing the PropertyPath is tempting as it supports traversing nested properties as you point out and indexes. You could write similar functionality yourself, I have myself in the past but it involves semi-complicated text parsing and lots of reflection work.

As Andrew points out you can simply reuse the PropertyPath from WPF. I'm assuming you just want to evaluate that path against an object that you have in which case the code is a little involved. To evaluate the PropertyPath it has to be used in a Binding against a DependencyObject. To demonstrate this I've just created a simple DependencyObject called BindingEvaluator which has a single DependencyProperty. The real magic then happens by calling BindingOperations.SetBinding which applies the binding so we can read the evaluated value.

var path = new PropertyPath("FullName.FirstName");

var binding = new Binding();
binding.Source = new Person { FullName = new FullName { FirstName = "David"}}; // Just an example object similar to your question
binding.Path = path;
binding.Mode = BindingMode.TwoWay;

var evaluator = new BindingEvaluator();
BindingOperations.SetBinding(evaluator, BindingEvaluator.TargetProperty, binding);
var value = evaluator.Target;
// value will now be set to "David"


public class BindingEvaluator : DependencyObject
{
    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.Register(
            "Target", 
            typeof (object), 
            typeof (BindingEvaluator));

    public object Target
    {
        get { return GetValue(TargetProperty); }
        set { SetValue(TargetProperty, value); }
    }
}

If you wanted to extend this you could wire up the PropertyChanged events to support reading values that change. I hope this helps!

13
ответ дан 6 December 2019 в 19:41
поделиться

Я не вижу причин, по которым вы не могли бы использовать его повторно.

См. PropertyPath :

Реализует структуру данных для описывая свойство как путь ниже другое имущество или ниже владения тип. Пути к свойствам используются в данных привязка к объектам и в раскадровках и временные рамки для анимации.

0
ответ дан 6 December 2019 в 19:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: