【问题标题】:Drag circles with scaleLinear initial position使用 scaleLinear 初始位置拖动圆圈
【发布时间】:2019-06-10 16:55:04
【问题描述】:

我无法在图表中拖动圆圈。这是现场演示https://codesandbox.io/s/71loxoq65j

我的图表

import { event, select, Selection } from "d3-selection";
import { scaleLinear, ScaleLinear } from "d3-scale";
import { Axis, axisBottom, axisLeft } from "d3-axis";
import { line, Line } from "d3-shape";
import { drag } from "d3-drag";

interface IMargin {
  left: number;
  right: number;
  top: number;
  bottom: number;
}

interface IConfig {
  height: number;
  margin: IMargin;
  target: SVGSVGElement;
  width: number;
}

interface ISample {
  x: number;
  y: number;
}

export default class Trigger {
  private chart: Selection<SVGGElement, {}, null, undefined>;
  private xScale: ScaleLinear<number, number>;
  private yScale: ScaleLinear<number, number>;
  private xAxis: Axis<number>;
  private xAxisGroup: Selection<SVGGElement, {}, null, undefined>;
  private yAxis: Axis<number>;
  private yAxisGroup: Selection<SVGGElement, {}, null, undefined>;

  constructor(config: IConfig) {
    const w = config.width - config.margin.left - config.margin.right;
    const h = config.height - config.margin.top - config.margin.bottom;

    // create global chart object
    this.chart = select(config.target)
      .attr("width", config.width)
      .attr("height", config.height)
      .append("g")
      .attr(
        "transform",
        `translate(${config.margin.left}, ${config.margin.top})`
      );

    // create x scale function
    this.xScale = scaleLinear()
      .domain([0, 100])
      .range([0, w]);

    // create y scale function
    this.yScale = scaleLinear()
      .domain([0, 100])
      .range([h, 0]);

    // create x axis function
    this.xAxis = (axisBottom(this.xScale) as Axis<number>).ticks(5);

    // create y axis function
    this.yAxis = (axisLeft(this.yScale) as Axis<number>).ticks(5);

    // append x axis to chart and call xAxis function
    this.xAxisGroup = this.chart
      .append("g")
      .attr("class", "x axis")
      .attr("transform", `translate(0, ${h})`)
      .call(this.xAxis);

    // append y axis to chart and call yAxis function
    this.yAxisGroup = this.chart
      .append("g")
      .attr("class", "y axis")
      .call(this.yAxis);

    // add x axis description
    this.chart
      .append("text")
      .attr("x", w / 2)
      .attr("y", h + config.margin.bottom)
      .style("text-anchor", "middle")
      .text("foo");

    // add y axis description
    this.chart
      .append("text")
      .attr("x", -h / 2)
      .attr("y", -config.margin.left)
      .attr("transform", "rotate(-90)")
      .attr("text-anchor", "middle")
      .attr("alignment-baseline", "hanging")
      .text("bar");
  }

  public yellow(data: ISample[]) {
    // draw circles
    this.chart
      .selectAll("circle")
      .data(data)
      .enter()
      .append("circle")
      .attr("cx", d => this.xScale(d.x))
      .attr("cy", d => this.yScale(d.y))
      .attr("r", 8)
      .attr("fill", "orange")
      .attr("class", "circle")
      .call(
        drag().on("drag", function(d) {
          select(this).attr("cx", (d.x = event.x));
        })
      );
  }
}

还有我调用图表的组件

import * as React from "react";
import { render } from "react-dom";
import Chart from "./chart";

import "./styles.css";

const Trigger = () => {
  const chart: React.MutableRefObject<Chart | null> = React.useRef(null);

  const chartRef = React.useRef(null);

  const [start, setStart] = React.useState(20);
  const [end, setEnd] = React.useState(50);

  // run on did mount but never again
  React.useEffect(() => {
    chart.current = new Chart({
      height: 320,
      margin: {
        bottom: 40,
        left: 50,
        right: 20,
        top: 10
      },
      target: chartRef.current!,
      width: 640
    });

    const yellow = [{ x: start, y: 50 }, { x: end, y: 50 }];
    chart.current.yellow(yellow);
  }, []);

  return (
    <div>
      <svg ref={chartRef} />
    </div>
  );
};

const rootElement = document.getElementById("root");
render(<Trigger />, rootElement);

如您所见,第一次拖动时的初始位置是错误的。它总是从0 开始。圆圈跳到左边。之后一切都很好,并且按预期工作。我试着按照这个简单的例子https://bl.ocks.org/mbostock/22994cc97fefaeede0d861e6815a847e,但它没有任何刻度。

我做错了什么?

最好的问候, 米尔科

【问题讨论】:

    标签: javascript reactjs typescript d3.js


    【解决方案1】:

    需要将鼠标位置转换为图表的g

    import { event, select, Selection, mouse } from "d3-selection";
    
    
      public yellow(data: ISample[]) {
        // draw circles
        var that = this;
        this.chart
          .selectAll("circle")
          .data(data)
          .enter()
          .append("circle")
          .attr("cx", d => this.xScale(d.x))
          .attr("cy", d => this.yScale(d.y))
          .attr("r", 8)
          .attr("fill", "orange")
          .attr("class", "circle")
          .call(
            drag().on("drag", function(d) {
              select(this).attr("cx", (d.x = mouse(that.chart.node())[0]));
            })
          );
      }
    

    【讨论】:

    • 你让我走上了正轨。这是我的解决方案。 drag().on('drag', (d: ISample, i: number, group) =&gt; { const element = group[i]; const coordinates = mouse(element); const x = coordinates[0]; d.x = this.xScale.invert(x); select(element).attr('cx', x); })
    猜你喜欢
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    • 2021-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多