我有一个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,但这只是减少了代码量(这里以两种类型为例):
.selectAll('circle.node')
.data(this.nodes)
.enter();
//products
circle
.filter(node => node.type === EngagementType.Product)
.append("pattern")
.attr("id", d => `insightImage-${d.id}`)
.attr("patternContentUnits", "objectBoundingBox")
.attr("width", "100%")
.attr("height", "100%")
.attr("x", 0)
.attr("y", 0)
.append("image")
.attr("xlink:href", d => `https://tiktok.org/products/${d.id}/standard`) (fake link)
.attr("x", 0)
.attr("y", 0)
.attr("width", 1)
.attr("height", 1)
.attr('preserveAspectRatio', 'xMidYMid slice');
//communities
circle
.filter(node => node.type === EngagementType.Community)
.append("pattern")
.attr("id", d => `insightImageCom-${d.id}`)
.attr("patternContentUnits", "objectBoundingBox")
.attr("width", "100%")
.attr("height", "100%")
.attr("x", 0)
.attr("y", 0)
.append("image")
.attr("xlink:href", d => `https://tiktok.org/communities/${d.id}/standard`)
.attr("x", 0)
.attr("y", 0)
.attr("width", 1)
.attr("height", 1)
.attr('preserveAspectRatio', 'xMidYMid slice');
然后用如下样式属性填充圆圈:
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));
我对assets文件夹中的图像有类似的方法,我有一堆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')`)
什么都没出现!
关于如何不同地设置图像或如何消除如此多的重复的一些建议/帮助将是惊人的!
我确信有一种更简单的方法来设置背景图像,但是端点当然不同。
感谢您的帮助!
答案 0 :(得分:1)
您使用的数据对象可以是任何东西。最合适的模式是在将其附加到元素选择之前进行准备,以使您已经拥有所需的一切。
以下示例定义了一个数据结构,该数据结构从类型到每个类别不同的数据进行映射。这仅是一个示例,核心是.map()
函数中发生的事情:您向数据对象添加了一个或多个属性,以便可以在node.type
与编写方法之间建立联系模式恰好适合每个节点。
将需要一种类似的方式来从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));