首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用拖动和选择在svg上响应大数组呈现

使用拖动和选择在svg上响应大数组呈现
EN

Stack Overflow用户
提问于 2022-11-30 19:39:20
回答 3查看 51关注 0票数 3

我使用React + d3js在svg上呈现数据,我有一个包含如下数据的大数组

代码语言:javascript
运行
复制
const arrayItemExample = {
  id: 1,
  text: 'Some Text for node',
  x: 100,
  y: 300,
  selected: false,
  dragging: false
}

这类元素的清单可达数万份。主要问题是,当我单击或拖动呈现的元素时,会更新该元素上的数据:

代码语言:javascript
运行
复制
const handleDragStart = useCallback((id)=>{
  setData(data=>{
    return data.map(item=>{
      if(item.id === id){
        return {
          ...item,
          dragging: true
        }
      }
      return item
    })
  })
},[])

const handleSelect = useCallback((id)=>{
  setData(data=>{
    return data.map(item=>{
      if(item.id === id){
        return {
          ...item,
          selected: true
        }
      }
      return item
    })
  })
},[])

这两个函数都能很好地处理少量的数据,但是如果页面上有100个或更多的元素,那么单击或拖动元素会在元素重绘过程中减缓页面的速度。

是否有任何方法通过重绘其唯一的元素来更新特定元素中的数据?我不能使用组件的内部状态,因为我需要所选和可拖动元素的总数据:例如,我用ctrl选择了几个元素,当我开始拖动其中一个时,另一个也必须被拖动。

EN

回答 3

Stack Overflow用户

发布于 2022-12-02 21:47:55

D3数据集最常使用SVG呈现,这是一种保留模式的图形模型,易于使用,但性能有限。SVG图表通常可以处理大约1000个数据点。

自从D3 v4之后,您还可以选择使用canvas来呈现图表,这是一个即时模式的图形模型。使用画布,您可以预期呈现大约10,000个数据点,同时保持平滑的60 you交互

所以我的建议是使用画布而不是SVG。如果您有时间,我建议您改用WebGL。

票数 0
EN

Stack Overflow用户

发布于 2022-12-02 23:40:54

要更新数组中特定元素的数据而不重新绘制所有元素,可以结合使用useReducer钩子和useMemo钩子。useReducer钩子允许您定义一个还原器函数,它根据分派的操作更新状态。useMemo钩子允许您计算一个回忆录值,该值只有在某个依赖项发生变化时才会重新计算。

下面是一个示例,说明如何使用useReducer和useMemo挂钩来更新数组中特定元素的数据,而不必重新绘制所有元素:

代码语言:javascript
运行
复制
const [state, dispatch] = useReducer(reducer, initialState);

const data = useMemo(() => {
  return state.data.map(item => {
    if (item.id === state.selectedId) {
      return {
        ...item,
        selected: true
      };
    } else if (item.id === state.draggingId) {
      return {
        ...item,
        dragging: true
      };
    }
    return item;
  });
}, [state.data, state.selectedId, state.draggingId]);

const handleDragStart = useCallback((id) => {
  dispatch({ type: 'DRAG_START', id });
}, []);

const handleSelect = useCallback((id) => {
  dispatch({ type: 'SELECT', id });
}, []);

在上面的代码中,我们使用useReducer钩子定义了一个还原器函数。还原器函数接受当前状态和动作,并根据动作返回一个新状态。我们还定义了两个动作创建者,handleDragStart和handleSelect,它们分别分派DRAG_START和选择操作。

接下来,我们使用useMemo钩子来计算数据数组的回传版本。useMemo钩子接受返回要回传的值的函数和依赖项列表。在这种情况下,函数返回更新后的数据数组,并根据当前状态的selectedId和draggingId更新选定的和拖动的元素。

最后,我们使用React组件中的数据数组来呈现元素。由于数据数组是回忆录的,所以只有当状态中的selectedId或draggingId发生变化时,才会重新计算它,这将确保

票数 0
EN

Stack Overflow用户

发布于 2022-12-03 07:10:34

有几种方法可以优化数据的呈现以提高性能。

您可以采取的一种方法是在您的React组件中使用shouldComponentUpdate生命周期方法。此方法允许您控制组件何时更新,这有助于防止不必要的重新呈现。例如,您可以使用shouldComponentUpdate只在组件的选定或拖动支柱发生更改时重新呈现组件,而不是每次更新父组件的数据数组时重新呈现。

另一种方法是使用虚拟列表组件,例如react虚拟化库。虚拟化列表只呈现当前在屏幕上可见的元素,这可以显着地提高呈现大型数据列表的性能。

此外,优化d3.js代码以避免不必要的重呈现元素通常是一个好主意。例如,您可以使用.exit()和.enter()选择在d3中只更新从数据中添加或删除的元素,而不是每次数据更改时重新呈现整个元素列表。

要在React组件中使用shouldComponentUpdate方法,可以将该方法添加到组件类中,如下所示:

代码语言:javascript
运行
复制
class MyComponent extends React.Component {
  shouldComponentUpdate(nextProps) {
    // Only update the component if the selected or dragging prop has changed
    return this.props.selected !== nextProps.selected || this.props.dragging !== nextProps.dragging;
  }

  render() {
    // Render the component
  }
}

要使用react虚拟化库,可以从npm安装它,然后在代码中使用VirtualizedList组件,如下所示:

代码语言:javascript
运行
复制
import { VirtualizedList } from 'react-virtualized';

const MyList = ({ data }) => {
  return (
    <VirtualizedList
      data={data}
      // Specify the height and width of the list
      height={300}
      width={300}
      // Specify a function to render each item in the list
      renderItem={({ item, index }) => {
        return <MyComponent key={item.id} item={item} />;
      }}
    />
  );
};

下面是使用.exit()和.enter()选项在d3中只更新从数据中添加或删除的元素的示例,而不是每次数据更改时重新呈现整个元素列表:

代码语言:javascript
运行
复制
// Select all elements with the specified class
const elements = d3.selectAll('.my-element-class');

// Bind the data to the selection
const updatedElements = elements.data(myData);

// Remove any elements that are no longer in the data
updatedElements.exit().remove();

// Add new elements for any data that doesn't have a corresponding element
const newElements = updatedElements.enter().append('div')
  .classed('my-element-class', true)
  // Set the initial attributes of the new elements
  .attr('x', d => d.x)
  .attr('y', d => d.y)
  .text(d => d.text);

// Update the attributes of all elements, whether they are new or not
updatedElements.merge(newElements)
  .attr('x', d => d.x)
  .attr('y', d => d.y)
  .text(d => d.text);

此代码将使用类选择所有元素,将指定的数据绑定到所选内容,删除数据中不再包含的任何元素,为没有相应元素的任何数据添加新元素,并更新所有元素的属性,无论它们是否是新元素。这允许您只更新已更改的元素,而不是每次数据更改时重新呈现整个元素列表。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74633288

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档