提交 21c45c1f authored 作者: 祖铭松's avatar 祖铭松

feat: update

上级 8e2938ae
......@@ -5,9 +5,10 @@
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import * as Plot from '@observablehq/plot';
// import * as d3 from 'd3';
import { chartData } from '../mock';
import * as d3 from 'https://cdn.jsdelivr.net/npm/d3@7/+esm';
import PubSub from 'pubsub-js';
import { chartData } from '../mock';
// import { setLegend, setColor } from '../utils/index';
// 根节点实例
const chartRef = ref(null);
......@@ -24,25 +25,41 @@ const plotInstance = ref(null);
// 生成图表
const generateChart = (data) => {
const ret = options.value;
// console.log(ret);
plotInstance.value = Plot.plot({
width: ret.chart_width || 800,
height: ret.chart_height || 700,
let configObj = {
width: ret.chart_width || 700,
height: ret.chart_height || 600,
marginTop: ret.margin_top || 60,
marginRight: ret.margin_right || 60,
marginBottom: ret.margin_bottom || 60,
marginLeft: ret.margin_left || 60,
colors: ret.data_color_list || [],
maxNumber: Math.round(d3.max(data, (d) => d.number)),
legendPosition: ret.legend_position?.split(',') || [1, 0],
legendData: [
{ name: 'Normal', checked: true },
{ name: 'Tumor', checked: true }
]
};
plotInstance.value = Plot.plot({
width: configObj.width,
height: configObj.height,
marginTop: configObj.marginTop,
marginRight: configObj.marginRight,
marginBottom: configObj.marginBottom,
marginLeft: configObj.marginLeft,
color: {
legend: ret.show_legend,
range: ret.data_color_list || []
range: configObj.colors
},
x: {
grid: ret.show_x_gridLine,
domain: ['Normal', 'Tumor']
domain: configObj.legendData.map((item) => item.name)
},
y: {
grid: ret.show_y_gridLine,
domain: [0, 10]
domain: [0, configObj.maxNumber]
},
marks: [
Plot.ruleX([0]),
......@@ -110,6 +127,12 @@ const generateChart = (data) => {
})
]
});
// const svg = d3.create('svg').attr('width', configObj.width).attr('height', configObj.height);
// const color = setColor(configObj);
// setLegend({ ...configObj, color, svg });
// plotInstance.value.append(svg.node());
chartRef.value.appendChild(plotInstance.value);
};
......
......@@ -192,7 +192,7 @@ const dynamic_parameter = reactive({
//图例
show_legend: true,
legend_position: '1,1',
legend_position: '1,0.5',
//坐标轴
show_x_axis: true,
show_x_line: true,
......
import * as d3 from 'https://cdn.jsdelivr.net/npm/d3@7/+esm';
// color config
export const setColor = (config) => {
let colors = [];
if (Array.isArray(config.colors)) {
colors = !!config.colors.length ? config.colors : colors;
} else if (!!config.colors) {
colors = config.colors.split(',');
}
const legend = config.legendData.map(item => item.name)
return d3.scaleOrdinal(colors).domain(legend);
};
// legend
export const setLegend = (config) => {
let legendX = config.legendPosition[0] == 0 ? config.marginLeft : config.legendPosition[0] == 0.5 ? config.width / 2 - 40 : config.width - config.marginLeft;
let legendY = config.legendPosition[1] == 0 ? 0 : config.legendPosition[1] == 0.5 ? config.height / 2 : config.height - config.marginTop + 50;
config.svg.append('g')
// .attr('transform', `translate(200, 0)`)
.attr('transform', `translate(${legendX}, ${legendY})`)
.attr('cursor', 'pointer')
.selectAll()
.data(config.legendData)
.join('g')
.attr('class', 'legend-rect')
.attr('transform', (d, i) => `translate(0, ${i * 20})`)
.call((g) => g.append('rect').attr('class', 'rect-legend').attr('width', 15).attr('height', 15).attr('fill', d => config.color(d.name)))
.call((g) =>
g
.append('text')
.attr('x', 50)
.attr('y', 8)
.attr('dy', '0.3em')
.style('font', '13px sans-serif')
.text((d) => d.name)
);
legendActive(config);
};
// legend active
export const legendActive = (config) => {
const legend = config.svg.selectAll('.legend-rect')
legend.on('click', (e, d) => {
config.legendData = config.legendData.map(item => {
if (item.name === d.name) {
return { ...item, checked: !item.checked }
} else {
return { ...item }
}
})
// const currentLegend = config.legendData.find(item => item.name == d.name);
config.svg.selectAll('.rect-legend').data(config.legendData).attr('fill', (d) => d.checked ? config.color(d.name) : '#aaa');
// config.svg.selectAll(`.points-${currentLegend.name}`).attr('display', `${currentLegend.checked ? 'block' : 'none'}`)
})
}
......@@ -88,7 +88,7 @@ const generateChart = (data) => {
setTips(cluster);
// legend
configObj.show_legend && setLegend(configObj, data);
configObj.show_legend && setLegend(configObj);
// label
setLabel(configObj);
......
......@@ -86,8 +86,7 @@ export const setTips = (rect) => {
};
// legend
export const setLegend = (config, data) => {
export const setLegend = (config) => {
config.svg.append('g')
.attr('transform', `translate(${config.width - config.marginLeft - 70}, ${100})`)
.attr('cursor', 'pointer')
......@@ -107,21 +106,7 @@ export const setLegend = (config, data) => {
.text((d) => d.name)
);
legendActive(config, data);
};
// title
export const setLabel = (config) => {
config.svg.append('text')
.attr('x', config.width / 2)
.attr('y', 30)
.attr('fill', config.titleConfig.color)
.attr('font-size', `${config.titleConfig.fontSize}px`)
.attr('font-family', `${config.titleConfig.fontFamily}`)
.attr('font-style', `${config.titleConfig.fontStyle}`)
.attr('font-weight', `${config.titleConfig.fontWeight}`)
.style('text-anchor', 'middle')
.text(config.titleConfig.label);
legendActive(config);
};
// legend active
......@@ -141,6 +126,20 @@ export const legendActive = (config) => {
})
}
// title
export const setLabel = (config) => {
config.svg.append('text')
.attr('x', config.width / 2)
.attr('y', 30)
.attr('fill', config.titleConfig.color)
.attr('font-size', `${config.titleConfig.fontSize}px`)
.attr('font-family', `${config.titleConfig.fontFamily}`)
.attr('font-style', `${config.titleConfig.fontStyle}`)
.attr('font-weight', `${config.titleConfig.fontWeight}`)
.style('text-anchor', 'middle')
.text(config.titleConfig.label);
};
export const legendDataActive = (config) => {
const legend = config.svg.selectAll('.legend-rect')
const legendRect = legend.select('rect')
......
......@@ -34,7 +34,10 @@ const generateChart = (data) => {
let marginLeft = Number(ret.margin_left) || 120;
let legendPosition = ret.legend_position?.split(',') || [1, 0];
let colors = ret.data_color_list || ['#FF0000', '#0000FF'];
let legendData = ['M', 'F'];
let legendData = [
{ name: 'M', checked: true },
{ name: 'F', checked: true }
];
// 标题配置
const titleConfig = {
......
......@@ -8,7 +8,8 @@ export const setColor = (config) => {
} else if (!!config.colors) {
colors = config.colors.split(',');
}
return d3.scaleOrdinal(colors).domain(config.legendData);
const legend = config.legendData.map(item => item.name)
return d3.scaleOrdinal(colors).domain(legend);
};
// tips
......@@ -48,11 +49,13 @@ export const setLegend = (config) => {
config.svg.append('g')
.attr('transform', `translate(${legendX}, ${legendY})`)
.attr('cursor', 'pointer')
.selectAll()
.data(config.legendData)
.join('g')
.attr('class', 'legend-rect')
.attr('transform', (d, i) => `translate(0, ${i * 50})`)
.call((g) => g.append('rect').attr('width', 20).attr('height', 50).attr('fill', d => config.color(d)))
.call((g) => g.append('rect').attr("class", "dot-legend").attr('width', 20).attr('height', 50).attr('fill', d => config.color(d.name)))
.call((g) =>
g
.append('text')
......@@ -61,10 +64,31 @@ export const setLegend = (config) => {
.attr('dy', '0.3em')
.style('font', '10px sans-serif')
.style('text-anchor', 'middle')
.text((d) => d)
.text((d) => d.name)
);
legendActive(config);
};
// legend active
export const legendActive = (config) => {
const legend = config.svg.selectAll('.legend-rect');
legend.on('click', (e, d) => {
config.legendData = config.legendData.map(item => {
if (item.name === d.name) {
return { ...item, checked: !item.checked }
} else {
return { ...item }
}
})
const currentLegend = config.legendData.find(item => item.name == d.name);
config.svg.selectAll('.dot-legend').data(config.legendData).attr('fill', (d) => d.checked ? config.color(d.name) : '#aaa');
config.svg.selectAll(`.dot-${currentLegend.name}`).attr('display', `${currentLegend.checked ? 'block' : 'none'}`);
config.svg.select(`.elliptic-${currentLegend.name}`).attr('display', `${currentLegend.checked ? 'block' : 'none'}`);
})
}
// scale
export const setScale = (config, data) => {
......@@ -160,6 +184,7 @@ export const setElliptic = (config) => {
rects
.append('ellipse')
.attr('class', `elliptic-${config.legendData[0].name}`)
.attr('cx', `${config.ellipticM.cx}`)
.attr('cy', `${config.ellipticM.cy}`)
.attr('rx', `${config.ellipticM.rx}`)
......@@ -171,6 +196,7 @@ export const setElliptic = (config) => {
rects
.append('ellipse')
.attr('class', `elliptic-${config.legendData[1].name}`)
.attr('cx', `${config.ellipticF.cx}`)
.attr('cy', `${config.ellipticF.cy}`)
.attr('rx', `${config.ellipticF.rx}`)
......@@ -188,6 +214,7 @@ export const setPoint = (config, data) => {
.selectAll("text")
.data(data)
.join("text")
.attr("class", d => `dot-${d.group}`)
.attr("dy", "0.35em")
.attr("x", d => config.x(d.p1) + 7)
.attr("y", d => config.y(d.p2))
......
......@@ -32,8 +32,8 @@ export const setTips = (rect) => {
.style('top', event.offsetY + 15 + 'px')
.html(`
<div>${d.name}</div>
<div>x: ${d.PC1}</div>
<div>y: ${d.PC2}</div>
<div>PC1: ${d.PC1}</div>
<div>PC2: ${d.PC2}</div>
`);
})
.on('mouseleave', function () {
......@@ -84,6 +84,25 @@ export const setLegend = (config) => {
legendActive(config);
};
// legend active
export const legendActive = (config) => {
const legend = config.svg.selectAll('.legend-rect');
legend.on('click', (e, d) => {
config.legendData = config.legendData.map(item => {
if (item.name === d.name) {
return { ...item, checked: !item.checked }
} else {
return { ...item }
}
})
const currentLegend = config.legendData.find(item => item.name == d.name);
config.svg.selectAll('.dot-legend').data(config.legendData).attr('stroke', (d) => d.checked ? config.color(d.name) : '#aaa');
config.svg.selectAll(`.dot-${currentLegend.name}`).attr('display', `${currentLegend.checked ? 'block' : 'none'}`);
config.svg.select(`.elliptic-${currentLegend.name}`).attr('display', `${currentLegend.checked ? 'block' : 'none'}`);
})
}
// scale
export const setScale = (config, data) => {
......@@ -243,23 +262,3 @@ export const setLabel = (config) => {
.style('text-anchor', 'middle')
.text(`${config.titleConfig.label}`);
};
// legend active
export const legendActive = (config) => {
const legend = config.svg.selectAll('.legend-rect');
legend.on('click', (e, d) => {
config.legendData = config.legendData.map(item => {
if (item.name === d.name) {
return { ...item, checked: !item.checked }
} else {
return { ...item }
}
})
const currentLegend = config.legendData.find(item => item.name == d.name);
config.svg.selectAll('.dot-legend').data(config.legendData).attr('stroke', (d) => d.checked ? config.color(d.name) : '#aaa');
config.svg.selectAll(`.dot-${currentLegend.name}`).attr('display', `${currentLegend.checked ? 'block' : 'none'}`)
config.svg.select(`.elliptic-${currentLegend.name}`).attr('display', `${currentLegend.checked ? 'block' : 'none'}`)
})
}
\ No newline at end of file
......@@ -22,7 +22,7 @@ import ClusterHeatmapSecond from '../../components/ClusterHeatmapSecond/index.vu
import CircularHeatmap from '../../components/CircularHeatmap/index.vue';
import Test from '../../components/Test/index.vue';
const chartCurrent = ref(4);
const chartCurrent = ref(1);
const chartList = shallowRef([
{ title: '线性拟合图', value: 1, comName: LinearFitting },
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论