项目需要实现花瓣图,但是改图表在echarts,highCharts等案例中均未出现,有类似的韦恩图,但是和需求有所差距;
为实现该效果,静态图表上采取svg来手动绘制花瓣:
- 确定中心点,以该点为中心,向四周绘制椭圆,该图像为均等分布(椭圆圆心不在中心点,而是有一定的偏移度)
- 在中心点处,绘制花心,为一个圆形,用于展示多朵花瓣的交集
- 花瓣的长度,颜色均可调整
技术点1:svg绘制花瓣图
<svg id="flower-svg" :width="flowerWidth" :height=" flowerHeight ">
<!-- 动态生成花瓣 -->
<g class="flower-svg-leaf" transform="translate(320, 200)">
<g v-for="(leaf, index) in leafCount" :key="index" :transform="`rotate(${(index * 360) / leafCount}) translate(55, 0)`">
<!-- 椭圆,背景颜色来自于 colors 数组 -->
<!--
花瓣边框的颜色和透明度
stroke="rgb(255, 106, 0)" stroke-opacity="1"
-->
<ellipse class="svg-leaf-item-ellipse" :rx="leafSize.rx" :ry="leafSize.ry"
:fill="colors[index]" fill-opacity="0.5"></ellipse>
<!-- 椭圆的内部数据 -->
<text class="svg-leaf-item-text" font-size="12px" font-family="Arial" fill="#000000" text-anchor="end" dominant-baseline="middle"
transform="rotate(0)" dx="53" visibility="visible" dy="2">50</text>
<!-- 椭圆内部数据对应的外部标签 -->
<text class="svg-leaf-item-group" font-size="12px" font-family="Arial" fill="#000000" text-anchor="start"
dominant-baseline="middle" transform="rotate(0)" dy="2" dx="110" visibility="visible">Leaf {{ index + 1 }}</text>
</g>
</g>
<!-- 花心 -->
<g class="flower-svg-center" transform="translate(320, 200)">
<circle class="flower-svg-center-self" :r="leafSize.ry - 5" fill="rgb(241, 43, 11)" fill-opacity="0.5"
stroke="rgb(241, 43, 11)" stroke-opacity="0.5"></circle>
<text class="flower-svg-center-text" font-size="12px" font-family="Arial" fill="rgb(255, 255, 255)" visibility="visible"
text-anchor="middle" dominant-baseline="middle" dy="3">141</text>
</g>
</svg>
静态代码详解:
transform="translate(320, 200)"
,svg 的宽高分别为640,400,所以以偏移一半为中心<g v-for="(leaf, index) in leafCount" :key="index" :transform="rotate(${(index * 360) / leafCount}) translate(55, 0)
">:leafCount
为花瓣的数量,对应transform
为旋转角度,等分显示每一朵花瓣- 用
ellipse
来绘制椭圆,涉及的参数有长半轴,短半轴,填充颜色等一些基础配置,后期均改为动态参数
技术点2:el-select下拉框回显色卡
原始下拉框options为:
colorTemplates: [
{
name: "色系1",
value: "1",
colors: [
"rgba(255, 106, 0, 0.5)",
"rgba(255, 209, 26, 0.5)",
"rgba(255, 72, 0, 0.5)",
"rgba(255, 153, 51, 0.5)",
"rgba(204, 102, 0, 0.5)",
"rgba(255, 51, 51, 0.5)",
"rgba(255, 128, 0, 0.5)",
"rgba(204, 0, 102, 0.5)",
"rgba(255, 51, 153, 0.5)",
"rgba(204, 51, 0, 0.5)",
],
},
{
name: "色系2",
value: "2",
colors: [
"rgba(0, 153, 255, 0.5)",
"rgba(0, 102, 204, 0.5)",
"rgba(0, 72, 204, 0.5)",
"rgba(0, 204, 255, 0.5)",
"rgba(51, 204, 255, 0.5)",
"rgba(102, 255, 255, 0.5)",
"rgba(51, 102, 255, 0.5)",
"rgba(0, 255, 204, 0.5)",
"rgba(51, 255, 204, 0.5)",
"rgba(0, 153, 204, 0.5)",
],
},
{
name: "色系3",
value: "3",
colors: [
"rgba(34, 139, 34, 0.5)",
"rgba(0, 255, 0, 0.5)",
"rgba(0, 128, 0, 0.5)",
"rgba(60, 179, 113, 0.5)",
"rgba(0, 255, 127, 0.5)",
"rgba(144, 238, 144, 0.5)",
"rgba(34, 139, 34, 0.5)",
"rgba(127, 255, 0, 0.5)",
"rgba(46, 139, 87, 0.5)",
"rgba(85, 107, 47, 0.5)",
],
},
],
需要将每组对象中的颜色,以色卡的形式展示在下拉框中,并且在选项框中回显
下拉框展示色卡:在el-option
里面通过自定义内容,遍历color的十个颜色,拼接成色卡
<el-select
v-model="selectedTemplate"
placeholder=""
@change="handleTemplateChange"
style="width: 250px"
ref="selectRef"
>
<el-option
v-for="(template, index) in colorTemplates"
:key="index"
:label="template.name"
:value="template.name"
>
<div style="display: flex; gap: 5px">
<!-- 展示每个模板下的颜色方块 -->
<div
v-for="(color, colorIndex) in template.colors"
:key="colorIndex"
class="color-box"
:style="{
backgroundColor: color,
width: '20px',
height: '20px',
}"
></div>
</div>
</el-option>
</el-select>
选择框回显色卡:
- 首先,清空选择框绑定的默认值
selectedTemplate
(在此之前已经将该值传给Vuex),不能通过this.$refs["selectRef"].value
去修改【不应该直接修改通过 props 传递过来的数据,因为 Vue 会在每次重新渲染时重置这些值。】- 将色卡的十组数据,生成
svg
字符串,转化为base64
编码,以background:url()
的方式,回显到选择框中
getSvgString(colors) {
const svgContent = `
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="20">
${colors
.map(
(color, index) =>
`<rect x="${
index * 20
}" width="20" height="20" fill="${color}"/>`
)
.join("")}
</svg>
`;
// 将SVG内容转换为Base64
const base64EncodedSvg = btoa(unescape(encodeURIComponent(svgContent))); // btoa编码,encodeURIComponent避免特殊字符问题
// 返回Base64编码后的SVG字符串,用作背景图
this.selectSVG = `url('data:image/svg+xml;base64,${base64EncodedSvg}')`;
// console.log(this.$refs["selectRef"].$el.children[0].children[0]);
this.$refs["selectRef"].$el.children[0].children[0].setAttribute(
"style",
`background:${this.selectSVG};background-repeat:no-repeat;background-position:15px;`
);
},