Javascript 减少代码-添加svg图像的重复代码

Javascript 减少代码-添加svg图像的重复代码,javascript,d3.js,svg,Javascript,D3.js,Svg,我有一个svg图,其中有几种不同类型的节点,每种类型都有许多不同的节点,具有不同的用途 产品,, 社区, 事件, 项目, 产品组 我想设置每个节点的背景图像 这些组中每个组的每个节点都有自己的唯一ID。 这些节点的类型和ID可用于从端点检索所有类型的映像,但映像位于资产文件夹中的产品组除外 我正在尝试从1调用图像。端点和2。从资产文件夹中 我的端点表示不同的类型,并在其中解析ID: https://tiktok.org/products/${node.id}/standard https://

我有一个svg图,其中有几种不同类型的节点,每种类型都有许多不同的节点,具有不同的用途

产品,, 社区, 事件, 项目, 产品组

我想设置每个节点的背景图像

这些组中每个组的每个节点都有自己的唯一ID。 这些节点的类型和ID可用于从端点检索所有类型的映像,但映像位于资产文件夹中的产品组除外

我正在尝试从1调用图像。端点和2。从资产文件夹中

我的端点表示不同的类型,并在其中解析ID:

https://tiktok.org/products/${node.id}/standard

https://tiktok.org/communities/${node.id}/standard
我目前这样做的方法似乎非常低效,我不应该有重复的代码!我“附加”了一个svg图像和一个ID,然后我为node.types引用它们并解析它们的ID,但这只是一堆代码(这里有两种类型作为示例):

然后我用样式属性填充圆,如下所示:

  circle
    .filter(node => node.depth !== 0 && node.type === EngagementType.Product)
    .append('circle')
    .classed('Engagement-GraphNode', true)
    .classed('Engagement-GraphNodeBackground', true)
    .classed('Engagement-GraphLeaf', node => node && (node.depth === 4 && !node.isExtraNode))
    .style('fill', d => `url(#insightImage-${d.id})`)
    .style('opacity', node => (node.visible) ? 1 : 0)
    .style('visibility', node => (node.visible) ? 'visible' : 'hidden')
    .on('click', node => onClick(node));
  circle
    .filter(node => node.depth !== 0 && node.type === EngagementType.Community)
    .append('circle')
    .classed('Engagement-GraphNode', true)
    .classed('Engagement-GraphNodeBackground', true)
    .classed('Engagement-GraphLeaf', node => node && (node.depth === 4 && !node.isExtraNode))
    .style('fill', d => `url(#insightImageCom-${d.id})`)
    .style('opacity', node => (node.visible) ? 1 : 0)
    .style('visibility', node => (node.visible) ? 'visible' : 'hidden')
    .on('click', node => onClick(node));
对于资产文件夹中的图像,我有一个类似的方法,我有一堆images.svg,然后对产品组执行与上面相同的操作,但实际上单独调用它们会占用大量空间

在本例中,我通过节点的ID调用节点,以分别分配tha资产文件夹中的图像:

      circle
    .filter(node => node.type === EngagementType.ProductGroup && node.id === 'a6qb000000003olAAA')
    .append("pattern")
    .attr("id", `insightImageInitiative`)
    .attr("patternContentUnits", "objectBoundingBox")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("x", 0)
    .attr("y", 0)
    .append("image")
    .attr("xlink:href", './assets/d3-icons/initiative.svg')
    .attr("x", 0.2)
    .attr("y", 0.2)
    .attr("width", 0.60)
    .attr("height", 0.60)
    .attr('preserveAspectRatio', 'xMidYMid slice');
  circle
    .filter(node => node.type === EngagementType.ProductGroup && node.id === 'a6qb000000003okAAA')
    .append("pattern")
    .attr("id", `insightImageIndustry`)
    .attr("patternContentUnits", "objectBoundingBox")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("x", 0)
    .attr("y", 0)
    .append("image")
    .attr("xlink:href", './assets/d3-icons/industry.svg')
    .attr("x", 0.2)
    .attr("y", 0.2)
    .attr("width", 0.60)
    .attr("height", 0.60)
    .attr('preserveAspectRatio', 'xMidYMid slice');
我试着简单地使用样式(填充),但它对我不起作用

    .style('fill', d => `url('./assets/d3-icons/calendar.svg')`) 
    .style('fill', d => `url('https://tiktok.org/products/${d.id}/standard')`) 
什么也没有出现

关于如何不同地设置图像或如何消除如此多的重复的一些建议/帮助将是令人惊讶的

我确信有一种更简单的方法来设置背景图像,当然端点是不同的


如果你能帮忙,谢谢你

您使用的数据对象可以是任何对象。最合适的模式是在将其附加到“图元”选择之前进行准备,这样您就已经拥有了所需的一切

下面的示例定义了从类型到每个类别不同的数据的数据结构映射。这只是一个示例,其核心是
.map()
函数中发生的事情:向数据对象添加一个或多个属性,以便在
节点之间建立连接。键入
以及为每个节点编写模式所需的方法

需要使用类似的方法将ID连接到资产文件夹映像

有点奇怪,您为每个节点定义了一个模式,但只有在
node.depth!==0
但这需要您理解,请仅使用过滤器功能识别需要渲染圆的非顶级条目

const details = new Map([
    [EngagementType.Product, { path: 'products', prefix: 'insightImage'} ],
    [EngagementType.Community, { path: 'comunities', prefix: 'insightImageCom'} ],
    // and so on...
]);

// enhance your data, each node is a shallow copy with extra properties
const renderingData = this.nodes.map(node => Object.assign({
    patternId: `${details.get(node.type).prefix}-${d.id}`,
    imageUrl: `https://tiktok.org/${details.get(node.type).path}/${d.id}/standard`,
    isLeaf: node.depth === 4 && !node.isExtraNode
}, node));

const circle = d3.selectAll('circle.node')
    .data(renderingData)
    .enter();

// now it is straight forward
circle
    .append("pattern")
    .attr("id", d => node.patternId)
    .attr("patternContentUnits", "objectBoundingBox")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("x", 0)
    .attr("y", 0);
    .append("image")
    .attr("xlink:href", d => d.imageUrl)
    .attr("x", 0)
    .attr("y", 0)
    .attr("width", 1)
    .attr("height", 1)
    .attr('preserveAspectRatio', 'xMidYMid slice')
  // and now you filter for non-toplevel nodes
  .filter(node => node.depth !== 0)
    .append('circle')
    .classed('Engagement-GraphNode', true)
    .classed('Engagement-GraphNodeBackground', true)
    .classed('Engagement-GraphLeaf', node => node.isLeaf)
    .style('fill', d => `url(#${d.patternId})`)
    .style('opacity', node => (node.visible) ? 1 : 0)
    .style('visibility', node => (node.visible) ? 'visible' : 'hidden')
    .on('click', node => onClick(node));

使用
节点。在callbacksHow中键入
?我没有看到任何回调,sorrycallbacks===箭头函数我刚刚看到了这一点,我将检查它并尽快尝试使用它,谢谢。
const details = new Map([
    [EngagementType.Product, { path: 'products', prefix: 'insightImage'} ],
    [EngagementType.Community, { path: 'comunities', prefix: 'insightImageCom'} ],
    // and so on...
]);

// enhance your data, each node is a shallow copy with extra properties
const renderingData = this.nodes.map(node => Object.assign({
    patternId: `${details.get(node.type).prefix}-${d.id}`,
    imageUrl: `https://tiktok.org/${details.get(node.type).path}/${d.id}/standard`,
    isLeaf: node.depth === 4 && !node.isExtraNode
}, node));

const circle = d3.selectAll('circle.node')
    .data(renderingData)
    .enter();

// now it is straight forward
circle
    .append("pattern")
    .attr("id", d => node.patternId)
    .attr("patternContentUnits", "objectBoundingBox")
    .attr("width", "100%")
    .attr("height", "100%")
    .attr("x", 0)
    .attr("y", 0);
    .append("image")
    .attr("xlink:href", d => d.imageUrl)
    .attr("x", 0)
    .attr("y", 0)
    .attr("width", 1)
    .attr("height", 1)
    .attr('preserveAspectRatio', 'xMidYMid slice')
  // and now you filter for non-toplevel nodes
  .filter(node => node.depth !== 0)
    .append('circle')
    .classed('Engagement-GraphNode', true)
    .classed('Engagement-GraphNodeBackground', true)
    .classed('Engagement-GraphLeaf', node => node.isLeaf)
    .style('fill', d => `url(#${d.patternId})`)
    .style('opacity', node => (node.visible) ? 1 : 0)
    .style('visibility', node => (node.visible) ? 'visible' : 'hidden')
    .on('click', node => onClick(node));