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