韦恩图
效果:
实现:
图形使用venn.js
和d3.js
绘制
label使用元素定位绘制(可根据数据动态计算)
代码:
- tempalte
<div class="venn mgt-4 center-flex" v-else ref="vennBox" style="height: 140px;"><div class="venn-right" :style="{ left: lengedPos.rightX + 'px' }" ref="vennRight"><p class="color-666 fs-12 ellipsis lh-17">XXXX</p><p class="lh-20">720人</p></div><div class="venn-left" :style="{ right: lengedPos.leftX + 'px' }" ref="vennRight"><p class="color-666 fs-12 ellipsis lh-17">XXX</p><p class="lh-20">720人</p></div><div class="venn-bottom flex-align" ref="vennBottom"><div class="venn-text"><p class="color-666 fs-12 lh-17">XXXX</p><p class="lh-20">720人</p></div><img src="@/assets/img/dataApplication/bottom.png" /></div><div ref="vennContainer" class="venn-container" style="width: 325px;height: 120px;"></div></div>
- script
import * as d3 from 'd3';
import { VennDiagram } from 'venn.js';data() {return {intersectionNum: 20,lengedPos: {rightX: 0,leftX: 0},};},mounted() {this.$nextTick(() => {setTimeout(() => {this.renderVennDiagram()}, 100);})},methods: {renderVennDiagram() {const container = this.$refs.vennContainer;// 数据const sets = [{ sets: ['A'], size: 100, label: 'A' },{ sets: ['B'], size: 100, label: 'B' },{ sets: ['A', 'B'], size: this.intersectionNum, label: 'A ∩ B' }];// 绘制韦恩图const chart = VennDiagram().styled(false).width(325).height(120);const svg = d3.select(container).append('svg').attr('width', 325).attr('height', 120);svg.datum(sets).call(chart);this.$nextTick(() => {const gElement = document.querySelector('g.venn-area.venn-circle[data-venn-sets="B"]');const gRect = gElement.getBoundingClientRect();const parentRect = this.$refs.vennBox.getBoundingClientRect();this.lengedPos.rightX = gRect.left - parentRect.left + gRect.width + 2;const gAElement = document.querySelector('g.venn-area.venn-circle[data-venn-sets="A"]');const gARect = gAElement.getBoundingClientRect();this.lengedPos.leftX = parentRect.right - gARect.left + 0})},
- style
::v-deep .venn-container {>svg {transform: scaleY(0.95);}g {position: relative;}svg {text {fill: transparent;display: none;}}[data-venn-sets="A"] {fill: #1083FB;}[data-venn-sets="B"] {fill: #6CD3FF;}[data-venn-sets="A_B"] {fill: #FFC300;path {stroke: white;stroke-width: 2px;}}}.venn {position: relative;&-left {position: absolute;top: 15px;&::after {content: '';position: absolute;right: -17.23px;background: url(~@/assets/img/dataApplication/left.png) center/100% 100% no-repeat;top: 50%;transform: translateY(-50%);width: 17.23px;height: 4.8px;}}&-right {position: absolute;top: 15px;&::before {content: '';position: absolute;left: -21.06px;background: url(~@/assets/img/dataApplication/right.png) center/100% 100% no-repeat;top: 50%;transform: translateY(-50%);width: 21.06px;height: 4.8px;}}&-bottom {position: absolute;left: 50%;transform: translateX(-100%) translateY(100%);bottom: 37px;.venn-text {position: absolute;left: 0;top: -3px;}img {width: 84px;height: 20px;}&::after {width: 84px;height: 20px;display: inline-block;background: url(~@/assets/img/dataApplication/bottom.png) center/100% 100% no-repeat;content: '';position: absolute;right: 0;}.venn-text {position: absolute;left: 0;transform: translateX(-100%);}}
}