当前位置: 首页 > news >正文

d3.js研发两组比较的分面柱状图


d3.js研发两组比较的分面柱状图

可调整分面在图的上方还是下方,动态计算位置

下面是项目里封装好的方法 可以直接调用

import * as d3 from "d3";const CMCTwoGroup = (options = {}) => {let originContainer = document.querySelector("#chart-container"),originHeight = originContainer.offsetHeight,originWidth = originContainer.offsetWidth;let height = originHeight * (options.params.height / 100);let width = originWidth * (options.params.width / 100);const container = d3.select(options.container);let svg = container.select("svg");// 获取标签样式function getSvgTextStyle({text = "",fontSize = 14,fontFamily = "Arial",fontWeight = "normal"} = {}) {const svg = d3.select("body").append("svg").attr("class", "get-svg-text-style");const textStyle = svg.append("text").text(text).attr("font-size", fontSize).attr("font-family", fontFamily).attr("font-weight", fontWeight).node().getBBox();svg.remove();return {width: textStyle.width,height: textStyle.height};}// 获取线性坐标轴宽高function getSvgBandAxisStyle({fontSize = 20,orient = "bottom",fontFamily = "Arial",fontWeight = "normal",rotate = 0,domain = ["A", "B", "C"],range = [0, 200]} = {}) {let axis;let svg = d3.select("body").append("svg").attr("width", 200).attr("height", 100).attr("transform", "translate(300, 200)").attr("class", "get-svg-axis-style");let scale = d3.scaleBand().domain(domain).range(range);if (orient === "bottom" || orient === "top") {axis = d3.axisBottom(scale);} else {axis = d3.axisLeft(scale);}let axisStyle = svg.append("g").call(axis).call((g) => {g.selectAll("text").attr("fill", "#555").attr("font-size", fontSize).attr("font-family", fontFamily).attr("font-weight", fontWeight).attr("tmpY",g.select("text").attr("tmpY") || g.select("text").attr("dy")).attr("dy",rotate > 70 && rotate <= 90? "0.35em": rotate >= -90 && rotate < -70? "0.4em": g.select("text").attr("tmpY")).attr("text-anchor",orient === "left"? "end": rotate? rotate > 0? "start": "end": "middle").attr("transform",`translate(0, 0) ${rotate ? `rotate(${rotate} 0 ${g.select("text").attr("y")})` : ""}`);}).node().getBBox();svg.remove();return {width: axisStyle.width,height: axisStyle.height};}const rawData = options.data;// 数据预处理const divisions = Array.from(new Set(rawData.map((d) => d.Matrisome_Division)) // 去重).sort((a, b) => {// 按原始数据出现顺序排序return (rawData.findIndex((d) => d.Matrisome_Division === a) -rawData.findIndex((d) => d.Matrisome_Division === b));});const groupedData = d3.group(rawData, (d) => d.Matrisome_Division);// 生成分类顺序(保持大分类顺序)const orderedCategories = [];divisions.forEach((division) => {const seen = new Set();rawData.forEach((d) => {if (d.Matrisome_Division === division &&!seen.has(d.Matrisome_Category)) {seen.add(d.Matrisome_Category);orderedCategories.push(d.Matrisome_Category);}});});// 构建处理后的数据结构const processedData = orderedCategories.map((category) => {const division = rawData.find((d) => d.Matrisome_Category === category).Matrisome_Division;return {category,division,Up:rawData.find((d) => d.Matrisome_Category === category && d.Regulation === "Up")?.Number || 0,Down:rawData.find((d) => d.Matrisome_Category === category && d.Regulation === "Down")?.Number || 0};});// 配置参数let {bar_witdh = 35,up_color = "#66c2a5",down_color = "#fc8d62",isNumber = true,numberSize = 10,division_color = "#f0f0f0",division_postion = "top",class_label_font = "Arial",class_label_size = 12,class_label_color = "#000000",x_title = "111",x_title_color = "#000",x_title_font = "Arial",x_title_size = 14,x_text_rotate = -45,x_text_color = "#000000",x_text_size = 14,x_text_font = "Arial",y_title = "222",y_title_color = "#000",y_title_font = "Arial",y_title_size = 14,y_text_color = "#000000",y_text_size = 14,y_text_font = "Arial",main_title = "333",main_title_color = "#000",main_title_font = "Arial",main_title_size = 14} = options.params;x_text_rotate = -x_text_rotate;const mainTitleH = main_title? getSvgTextStyle({text: main_title,fontSize: main_title_size,fontFamily: main_title_font}).height + 20: 0;const xTitleH = x_title? getSvgTextStyle({text: x_title,fontSize: x_title_size,fontFamily: x_title_font}).height + 20: 0;const xAxisH =getSvgBandAxisStyle({fontSize: x_text_size,fontFamily: x_text_font,rotate: x_text_rotate,domain: orderedCategories}).height + 20;const yTitleH = y_title? getSvgTextStyle({text: y_title,fontSize: y_title_size,fontFamily: y_title_font}).height + 20: 0;const yAxisW =getSvgBandAxisStyle({fontSize: y_text_size,fontFamily: y_text_font,domain: [0, d3.max(processedData, (d) => Math.max(d.Up, d.Down)) * 1.2],orient: "left"}).width + 20;let margin = {top: 50 + mainTitleH,right: 80,bottom: xAxisH + xTitleH + 100,left: yAxisW + yTitleH};// 创建SVG画布if (svg.empty()) {svg = container.append("svg");} else {svg.selectAll("*").remove();}svg.attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);// 比例尺配置const xScale = d3.scaleBand().domain(orderedCategories).range([margin.left + yAxisW, width]).paddingInner(0).paddingOuter(0);const xSubgroup = d3.scaleBand().domain(["Up", "Down"]).range([xScale.bandwidth() / 2 - bar_witdh,xScale.bandwidth() / 2 + bar_witdh]).padding(0);const yMax = d3.max(processedData, (d) => Math.max(d.Up, d.Down)) * 1.2;const yScale = d3.scaleLinear().domain([0, yMax]).range([height, margin.top]).nice();// 颜色方案const color = d3.scaleOrdinal().domain(["Up", "Down"]).range([up_color, down_color]);const divisionColor = d3.scaleOrdinal().domain(divisions).range([division_color]);//  绘制柱状图svg.append("g").selectAll("g").data(processedData).join("g").attr("transform", (d) => `translate(${xScale(d.category)},0)`).selectAll("rect").data((d) =>["Up", "Down"].map((reg) => ({reg,value: d[reg],category: d.category}))).join("rect").attr("class", "bar").attr("x", (d) => xSubgroup(d.reg)).attr("y", (d) => yScale(d.value)).attr("width", bar_witdh).attr("height", (d) => height - yScale(d.value)).attr("fill", (d) => color(d.reg));//  添加数值标签if (isNumber) {svg.append("g").selectAll("text").data(processedData.flatMap((d) =>["Up", "Down"].map((reg) => ({category: d.category,value: d[reg],x: xScale(d.category) + xSubgroup(reg) + bar_witdh / 2,y: yScale(d[reg])})))).join("text").text((d) => d.value).attr("x", (d) => d.x).attr("y", (d) => d.y - 5) // 在柱子顶部上方5px.style("text-anchor", "middle").style("font-size", numberSize).style("fill", "#333");}// 主标题svg.append("text").attr("class", "main-title").attr("x", (width + margin.right) / 2).attr("y", division_postion == "bottom" ? 40 : 20).text(main_title).attr("text-anchor", "middle").attr("font-family", main_title_font).attr("font-size", main_title_size).attr("fill", main_title_color);// X轴标题svg.append("text").attr("class", "axis-title").attr("x", (width + margin.right) / 2).attr("y",division_postion == "bottom" ? height + xAxisH + 60 : height + xAxisH + 20).text(x_title).attr("text-anchor", "middle").attr("font-family", x_title_font).attr("font-size", x_title_size).attr("fill", x_title_color);// Y轴标题svg.append("text").attr("class", "axis-title").attr("transform", `rotate(-90)`).attr("x", -height / 2).attr("y", margin.left - 40).text(y_title).attr("text-anchor", "middle").attr("font-family", y_title_font).attr("font-size", y_title_size).attr("fill", y_title_color);//  y坐标轴svg.append("g").attr("transform", `translate(${margin.left + yAxisW}, 0)`).call(d3.axisLeft(yScale)).append("text").attr("stroke", "#333").attr("stroke-width", 1.5).attr("fill", "none").attr("shape-rendering", "crispEdges");svg.selectAll(".tick text").attr("font-family", y_text_font).style("font-size", y_text_size).style("fill", y_text_color);//  大分类背景const divisionRanges = [];let currentDivision = null;let startCategory = null;processedData.forEach((d, i) => {if (d.division !== currentDivision) {if (currentDivision) {const end = xScale(processedData[i - 1].category) + xScale.bandwidth();divisionRanges.push({division: currentDivision,start: xScale(startCategory),end: end,width: end - xScale(startCategory)});}currentDivision = d.division;startCategory = d.category;}// 处理最后一个元素if (i === processedData.length - 1) {const end = xScale(d.category) + xScale.bandwidth();divisionRanges.push({division: currentDivision,start: xScale(startCategory),end: end,width: end - xScale(startCategory)});}});// 绘制背景块svg.selectAll(".division-block").data(divisionRanges).join("rect").attr("class", "division-block").attr("x", (d) => d.start).attr("width", (d) => d.width).attr("y", division_postion == "bottom" ? height : main_title ? 45 : 10).attr("height", 40).attr("fill", (d) => divisionColor(d.division)).attr("stroke", "#000000").attr("stroke-width", 1);// 添加分类标签svg.selectAll(".division-label").data(divisionRanges).join("text").text((d) => d.division).attr("x", (d) => d.start + d.width / 2).attr("y",division_postion == "bottom" ? height + 20 : main_title ? 65 : 30).style("dominant-baseline", "middle").attr("text-anchor", "middle").attr("font-family", class_label_font).style("font-size", class_label_size).style("fill", class_label_color);// 坐标轴const xAxis = d3.axisBottom(xScale).tickValues(orderedCategories) // 使用分类数据作为刻度.tickFormat((d) => d);// 绘制X轴svg.append("g").attr("class", "x-axis").attr("transform",`translate(0,${division_postion == "bottom" ? height + 40 : height})`) // 定位到图表底部.call(xAxis).call((g) => {g.selectAll(".tick text").attr("fill", x_text_color).attr("font-size", x_text_size).attr("font-family", x_text_font).each(function () {const text = d3.select(this);text.attr("tmpY", text.attr("dy") || "0.71em"); // 保存原始偏移量}).attr("dy", (d, i, nodes) => {const rotate = x_text_rotate;if (rotate > 70 && rotate <= 90) return "0.35em";if (rotate >= -90 && rotate < -70) return "0.4em";return d3.select(nodes[i]).attr("tmpY");}).attr("text-anchor",x_text_rotate ? (x_text_rotate > 0 ? "start" : "end") : "middle").attr("transform",(d, i, nodes) =>`rotate(${x_text_rotate} 0 ${d3.select(nodes[i]).attr("y")})`);});// 图例const legend = svg.append("g").attr("transform", `translate(${width + 40}, ${height / 2 - 20})`) // 右侧居中.selectAll("g").data(["Up", "Down"]).enter().append("g").attr("transform", (d, i) => `translate(0,${i * 25})`); // 增加行间距legend.append("rect").attr("width", 18).attr("height", 18).attr("fill", color);legend.append("text").attr("x", 24).attr("y", 9).attr("dy", "0.32em").style("font-size", "12px") // 添加字体大小.text((d) => d);
};export default CMCTwoGroup;

调用方法:

  CMCTwoGroup({data: plots,params: chartParam,container: "#bar-container"});

 再附赠一个研发初期没封装的html版的吧!可以直接运行!

<!DOCTYPE html>
<html><head> </head><body><div id="chart"></div></body>
</html>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>// 获取标签样式function getSvgTextStyle({text = "",fontSize = 14,fontFamily = "Arial",fontWeight = "normal"} = {}) {const svg = d3.select("body").append("svg").attr("class", "get-svg-text-style");const textStyle = svg.append("text").text(text).attr("font-size", fontSize).attr("font-family", fontFamily).attr("font-weight", fontWeight).node().getBBox();svg.remove();return {width: textStyle.width,height: textStyle.height};}// 获取线性坐标轴宽高function getSvgBandAxisStyle({fontSize = 20,orient = "bottom",fontFamily = "Arial",fontWeight = "normal",rotate = 0,domain = ["A", "B", "C"],range = [0, 200]} = {}) {let axis;let svg = d3.select("body").append("svg").attr("width", 200).attr("height", 100).attr("transform", "translate(300, 200)").attr("class", "get-svg-axis-style");let scale = d3.scaleBand().domain(domain).range(range);if (orient === "bottom" || orient === "top") {axis = d3.axisBottom(scale);} else {axis = d3.axisLeft(scale);}let axisStyle = svg.append("g").call(axis).call((g) => {g.selectAll("text").attr("fill", "#555").attr("font-size", fontSize).attr("font-family", fontFamily).attr("font-weight", fontWeight).attr("tmpY",g.select("text").attr("tmpY") || g.select("text").attr("dy")).attr("dy",rotate > 70 && rotate <= 90? "0.35em": rotate >= -90 && rotate < -70? "0.4em": g.select("text").attr("tmpY")).attr("text-anchor",orient === "left"? "end": rotate? rotate > 0? "start": "end": "middle").attr("transform",`translate(0, 0) ${rotate ? `rotate(${rotate} 0 ${g.select("text").attr("y")})` : ""}`);}).node().getBBox();svg.remove();return {width: axisStyle.width,height: axisStyle.height};}const rawData = [{Matrisome_Division: "Matrisome-associated",Matrisome_Category: "ECM Regulators",Regulation: "Down",Number: 4},{Matrisome_Division: "Matrisome-associated",Matrisome_Category: "ECM-affiliated Proteins",Regulation: "Down",Number: 3},{Matrisome_Division: "Core matrisome",Matrisome_Category: "ECM Glycoproteins",Regulation: "Up",Number: 2},{Matrisome_Division: "Matrisome-associated",Matrisome_Category: "ECM Regulators",Regulation: "Up",Number: 2},{Matrisome_Division: "Matrisome-associated",Matrisome_Category: "Secreted Factors",Regulation: "Up",Number: 2},{Matrisome_Division: "Core matrisome",Matrisome_Category: "ECM Glycoproteins",Regulation: "Down",Number: 1},{Matrisome_Division: "Matrisome-associated",Matrisome_Category: "ECM-affiliated Proteins",Regulation: "Up",Number: 1},{Matrisome_Division: "Matrisome-associated",Matrisome_Category: "Secreted Factors",Regulation: "Down",Number: 0}];// 数据预处理const divisions = Array.from(new Set(rawData.map((d) => d.Matrisome_Division)) // 去重).sort((a, b) => {// 按原始数据出现顺序排序return (rawData.findIndex((d) => d.Matrisome_Division === a) -rawData.findIndex((d) => d.Matrisome_Division === b));});const groupedData = d3.group(rawData, (d) => d.Matrisome_Division);// 生成分类顺序(保持大分类顺序)const orderedCategories = [];divisions.forEach((division) => {const seen = new Set();rawData.forEach((d) => {if (d.Matrisome_Division === division &&!seen.has(d.Matrisome_Category)) {seen.add(d.Matrisome_Category);orderedCategories.push(d.Matrisome_Category);}});});// 构建处理后的数据结构const processedData = orderedCategories.map((category) => {const division = rawData.find((d) => d.Matrisome_Category === category).Matrisome_Division;return {category,division,Up:rawData.find((d) => d.Matrisome_Category === category && d.Regulation === "Up")?.Number || 0,Down:rawData.find((d) => d.Matrisome_Category === category && d.Regulation === "Down")?.Number || 0};});// 配置参数let // {bar_witdh = 35,bar_up_color = "#66c2a5",bar_down_color = "#fc8d62",opacity = 0.5,isNumber = true,division_color = "#f0f0f0",division_postion = "bottom",class_label_font = "Arial",class_label_size = 12,class_label_color = "#000000",x_title = "111",x_title_color = "#000",x_title_font = "Arial",x_title_size = 14,x_text_rotate = -45,x_text_color = "#000000",x_text_size = 14,x_text_font = "Arial",y_title = "222",y_title_color = "#000",y_title_font = "Arial",y_title_size = 14,y_text_color = "#000000",y_text_size = 14,y_text_font = "Arial",main_title = "333",main_title_color = "#000",main_title_font = "Arial",main_title_size = 14;// } = options.params;const mainTitleH = main_title? getSvgTextStyle({text: main_title,fontSize: main_title_size,fontFamily: main_title_font}).height + 20: 0;const xTitleH = x_title? getSvgTextStyle({text: x_title,fontSize: x_title_size,fontFamily: x_title_font}).height + 20: 0;const xAxisH =getSvgBandAxisStyle({fontSize: x_text_size,fontFamily: x_text_font,rotate: x_text_rotate,domain: orderedCategories}).height + 20;const yTitleH = y_title? getSvgTextStyle({text: y_title,fontSize: y_title_size,fontFamily: y_title_font}).height + 20: 0;const yAxisW =getSvgBandAxisStyle({fontSize: y_text_size,fontFamily: y_text_font,domain: [0, d3.max(processedData, (d) => Math.max(d.Up, d.Down)) * 1.2],orient: "left"}).width + 20;const margin = {top: 40 + mainTitleH,right: 150,bottom: xAxisH + xTitleH + 100,left: yAxisW + yTitleH};const width = 600;const height = 400;const svg = d3.select("#chart").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform", `translate(${margin.left},${margin.top})`);// 比例尺配置const xScale = d3.scaleBand().domain(orderedCategories).range([0, width]).paddingInner(0).paddingOuter(0);const xSubgroup = d3.scaleBand().domain(["Up", "Down"]).range([xScale.bandwidth() / 2 - bar_witdh,xScale.bandwidth() / 2 + bar_witdh]).padding(0);const yMax = d3.max(processedData, (d) => Math.max(d.Up, d.Down)) * 1.2;const yScale = d3.scaleLinear().domain([0, yMax]).range([height, 0]).nice();// 颜色方案const color = d3.scaleOrdinal().domain(["Up", "Down"]).range([bar_up_color, bar_down_color]);const divisionColor = d3.scaleOrdinal().domain(divisions).range([division_color]);//  绘制柱状图svg.append("g").selectAll("g").data(processedData).join("g").attr("transform", (d) => `translate(${xScale(d.category)},0)`).selectAll("rect").data((d) =>["Up", "Down"].map((reg) => ({reg,value: d[reg],category: d.category}))).join("rect").attr("class", "bar").attr("x", (d) => xSubgroup(d.reg)).attr("y", (d) => yScale(d.value)).attr("width", bar_witdh).attr("height", (d) => height - yScale(d.value)).attr("fill", (d) => color(d.reg)).attr("fill-opacity", opacity);//  添加数值标签if (isNumber) {svg.append("g").selectAll("text").data(processedData.flatMap((d) =>["Up", "Down"].map((reg) => ({category: d.category,value: d[reg],x: xScale(d.category) + xSubgroup(reg) + bar_witdh / 2,y: yScale(d[reg])})))).join("text").text((d) => d.value).attr("x", (d) => d.x).attr("y", (d) => d.y - 5) // 在柱子顶部上方5px.style("text-anchor", "middle").style("font-size", "10px").style("fill", "#333");}// 主标题svg.append("text").attr("class", "chart-title").attr("x", width / 2).attr("y", -40).text(main_title).attr("text-anchor", "middle").attr("font-family", main_title_font).attr("font-size", main_title_size).attr("fill", main_title_color);// X轴标题svg.append("text").attr("class", "axis-title").attr("x", width / 2).attr("y",division_postion == "bottom" ? height + xAxisH + 60 : height + xAxisH + 20).text(x_title).attr("text-anchor", "middle").attr("font-family", x_title_font).attr("font-size", x_title_size).attr("fill", x_title_color);// Y轴标题svg.append("text").attr("class", "axis-title").attr("transform", `rotate(-90)`).attr("x", -height / 2).attr("y", -50).text(y_title).attr("text-anchor", "middle").attr("font-family", y_title_font).attr("font-size", y_title_size).attr("fill", y_title_color);// y轴svg.append("g").call(d3.axisLeft(yScale)).append("text").attr("fill", "#000").attr("transform", "rotate(-90)").attr("y", 6).attr("dy", "0.71em").attr("text-anchor", "end");//  坐标轴svg.append("g").call(d3.axisLeft(yScale)).append("text").attr("stroke", "#333").attr("stroke-width", 1.5).attr("fill", "none").attr("shape-rendering", "crispEdges").selectAll(".tick text").attr("font-family", y_text_font).style("font-size", y_text_size).style("fill", y_text_color);//  大分类背景const divisionRanges = [];let currentDivision = null;let startCategory = null;processedData.forEach((d, i) => {if (d.division !== currentDivision) {if (currentDivision) {const end = xScale(processedData[i - 1].category) + xScale.bandwidth();divisionRanges.push({division: currentDivision,start: xScale(startCategory),end: end,width: end - xScale(startCategory)});}currentDivision = d.division;startCategory = d.category;}// 处理最后一个元素if (i === processedData.length - 1) {const end = xScale(d.category) + xScale.bandwidth();divisionRanges.push({division: currentDivision,start: xScale(startCategory),end: end,width: end - xScale(startCategory)});}});// 绘制背景块svg.selectAll(".division-block").data(divisionRanges).join("rect").attr("class", "division-block").attr("x", (d) => d.start).attr("width", (d) => d.width).attr("y", division_postion == "bottom" ? height : 0).attr("height", 40).attr("fill", (d) => divisionColor(d.division)).attr("stroke", "#000000").attr("stroke-width", 1);// 添加分类标签svg.selectAll(".division-label").data(divisionRanges).join("text").text((d) => d.division).attr("x", (d) => d.start + d.width / 2).attr("y", division_postion == "bottom" ? height + 20 : 20).style("dominant-baseline", "middle").attr("text-anchor", "middle").attr("font-family", class_label_font).style("font-size", class_label_size).style("fill", class_label_color);// 坐标轴// 创建X轴生成器const xAxis = d3.axisBottom(xScale).tickValues(orderedCategories) // 使用分类数据作为刻度.tickFormat((d) => d); // 分类轴不需要数字格式化// 绘制X轴svg.append("g").attr("class", "x-axis").attr("transform",`translate(0,${division_postion == "bottom" ? height + 40 : height})`) // 定位到图表底部.call(xAxis).call((g) => {g.selectAll(".tick text").attr("fill", x_text_color).attr("font-size", x_text_size).attr("font-family", x_text_font).each(function () {const text = d3.select(this);text.attr("tmpY", text.attr("dy") || "0.71em"); // 保存原始偏移量}).attr("dy", (d, i, nodes) => {const rotate = x_text_rotate;if (rotate > 70 && rotate <= 90) return "0.35em";if (rotate >= -90 && rotate < -70) return "0.4em";return d3.select(nodes[i]).attr("tmpY");}).attr("text-anchor",x_text_rotate ? (x_text_rotate > 0 ? "start" : "end") : "middle").attr("transform",(d, i, nodes) =>`rotate(${x_text_rotate} 0 ${d3.select(nodes[i]).attr("y")})`);});// 图例const legend = svg.append("g").attr("transform", `translate(${width + 20}, ${height / 2 - 20})`) // 右侧居中.selectAll("g").data(["Up", "Down"]).enter().append("g").attr("transform", (d, i) => `translate(0,${i * 25})`); // 增加行间距legend.append("rect").attr("width", 18).attr("height", 18).attr("fill", color);legend.append("text").attr("x", 24).attr("y", 9).attr("dy", "0.32em").style("font-size", "12px") // 添加字体大小.text((d) => d);
</script>

HTML效果图:

 

完毕完毕! 


文章转载自:

http://qUr5aeCQ.qsyyp.cn
http://AiByZcfx.qsyyp.cn
http://ajd7Psub.qsyyp.cn
http://9qofpiHO.qsyyp.cn
http://U4mlAUuS.qsyyp.cn
http://ViHRhEQ1.qsyyp.cn
http://E9gcJl4o.qsyyp.cn
http://cDgcxApP.qsyyp.cn
http://Jm8PI83t.qsyyp.cn
http://R64iV7UD.qsyyp.cn
http://qv6LGsCe.qsyyp.cn
http://pwdQdHjL.qsyyp.cn
http://AvelO2Qi.qsyyp.cn
http://YUtprLFi.qsyyp.cn
http://gVT49QPx.qsyyp.cn
http://iFcyulvz.qsyyp.cn
http://FtBwpb0I.qsyyp.cn
http://rllssf54.qsyyp.cn
http://In899QlG.qsyyp.cn
http://GPvXeDAj.qsyyp.cn
http://IuoLDzKb.qsyyp.cn
http://dl6lAa5E.qsyyp.cn
http://DZprUzkR.qsyyp.cn
http://nlrlzpTr.qsyyp.cn
http://kATXcwRo.qsyyp.cn
http://mdPcsSmY.qsyyp.cn
http://7xYjSZP0.qsyyp.cn
http://FhBLD40S.qsyyp.cn
http://DvsPg5sN.qsyyp.cn
http://S8pt4bsC.qsyyp.cn
http://www.dtcms.com/a/246811.html

相关文章:

  • kali系统 windows Linux靶机入侵演练
  • QT5 隐藏控制台窗口方法2025.6.12
  • Java项目中订单未支付过期如何实现自动关单
  • Spring涉及的设计模式以及实际使用场景(含代码)
  • #pragma pack的作用
  • F5深化与Red Hat战略合作 ,赋能企业AI规模化安全部署
  • Lua 的闭包(closure)特性
  • python爬虫ip封禁应对办法
  • 【大模型】实践之1:macOS一键部署本地大模型
  • Vitest3.0 现已发布!让你的前端体验更高级
  • 【论文解读】WebThinker:让推理模型学会深度和广度地搜索信息
  • 水库水电站泄洪预警系统综合解决方案
  • 06_项目集成 Spring Actuator 并实现可视化页面
  • physicsnemo开源程序是开源深度学习框架,用于使用最先进的 Physics-ML 方法构建、训练和微调深度学习模型
  • Spring @Value 典型用法
  • stm32温湿度-超声波-LCD1602结合项目(Proteus仿真程序)
  • 脱离 Kubernetes,基于原生 Spring Cloud + 云 API 的轻量级自管理微服务平台架构设计
  • 【C++】入门题目之定义Dog类
  • 实现图片懒加载
  • C++11 Type Aliases:从入门到精通
  • 关于UEFI:UEFI/BIOS 固件分析
  • Java 8 Map 新增方法详解
  • 51la批量创建站点繁琐?悟空统计一站式高效解决方案
  • HALCON第四讲->几何变换
  • C++中的RAII技术:资源获取即初始化
  • 【C++】ImGui:不足半兆的桌面程序
  • DWS层新增指标处理方案
  • Vue3+TypeScript实现访问者模式
  • Lesson 27 A wet night
  • MySQL 和 PostgreSQL,到底选择哪个?