deepseek v3-0324 化学键线式Canvas编辑器设计
化学键线式Canvas编辑器设计
下面是一个基于HTML5 Canvas的化学键线式编辑器的基本实现方案。这个编辑器允许用户绘制有机化学中常见的键线式结构。
基本HTML结构
<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>化学键线式编辑器</title><style>body {font-family: Arial, sans-serif;margin: 20px;}#editor-container {display: flex;flex-direction: column;width: 800px;margin: 0 auto;}#toolbar {display: flex;margin-bottom: 10px;padding: 10px;background: #f0f0f0;border-radius: 5px;}.tool-btn {margin-right: 10px;padding: 5px 10px;cursor: pointer;}.tool-btn.active {background: #4CAF50;color: white;}#canvas-container {border: 1px solid #ccc;margin-bottom: 10px;}canvas {background: white;display: block;}#status {font-size: 12px;color: #666;}/* 添加到style部分 */#presets {margin: 15px 0;padding: 10px;background: #f8f8f8;border-radius: 5px;}#presets h3 {margin-top: 0;}.preset-btn {display: inline-block;margin: 5px;padding: 5px 10px;background: #e0e0e0;border-radius: 3px;cursor: pointer;}.preset-btn:hover {background: #d0d0d0;}#export-buttons {margin-top: 15px;}#export-buttons button {margin-right: 10px;padding: 8px 15px;background: #4CAF50;color: white;border: none;border-radius: 4px;cursor: pointer;}#export-buttons button:hover {background: #45a049;}</style>
</head><body><div id="editor-container"><h1>化学键线式编辑器</h1><div id="toolbar"><div class="tool-btn active" data-tool="select">选择</div><div class="tool-btn" data-tool="bond">单键</div><div class="tool-btn" data-tool="double-bond">双键</div><div class="tool-btn" data-tool="triple-bond">三键</div><div class="tool-btn" data-tool="wedge">楔形键</div><div class="tool-btn" data-tool="dash">虚线键</div><div class="tool-btn" data-tool="text">文本</div><div class="tool-btn" data-tool="erase">橡皮擦</div><div class="tool-btn" data-tool="clear">清空</div></div><!-- 在toolbar div后面添加以下内容 --><div id="presets"><h3>常用结构</h3><div class="preset-btn" data-preset="benzene">苯环</div><div class="preset-btn" data-preset="cyclohexane">环己烷</div><div class="preset-btn" data-preset="cyclopentane">环戊烷</div><div class="preset-btn" data-preset="methane">甲烷</div><div class="preset-btn" data-preset="ethane">乙烷</div><div class="preset-btn" data-preset="ethene">乙烯</div><div class="preset-btn" data-preset="ethyne">乙炔</div></div><div id="export-buttons"><button id="export-png">导出PNG</button><button id="export-svg">导出SVG</button><button id="copy-clipboard">复制到剪贴板</button></div><div id="canvas-container"><canvas id="chem-canvas" width="800" height="500"></canvas></div><div id="status">就绪</div></div><script src="editor.js"></script>
</body></html>
JavaScript实现 (editor.js)
document.addEventListener('DOMContentLoaded', function() {const canvas = document.getElementById('chem-canvas');const ctx = canvas.getContext('2d');const statusDiv = document.getElementById('status');const toolButtons = document.querySelectorAll('.tool-btn');let currentTool = 'select';let isDrawing = false;let startX, startY;let elements = [];let selectedElement = null;// 工具按钮点击事件toolButtons.forEach(button => {button.addEventListener('click', function() {toolButtons.forEach(btn => btn.classList.remove('active'));this.classList.add('active');currentTool = this.dataset.tool;statusDiv.textContent = `当前工具: ${this.textContent}`;});});// 鼠标事件处理canvas.addEventListener('mousedown', startDrawing);canvas.addEventListener('mousemove', draw);canvas.addEventListener('mouseup', stopDrawing);canvas.addEventListener('mouseout', stopDrawing);function startDrawing(e) {const rect = canvas.getBoundingClientRect();startX = e.clientX - rect.left;startY = e.clientY - rect.top;if (currentTool === 'select') {// 检查是否点击了现有元素selectedElement = getElementAtPosition(startX, startY);if (selectedElement) {isDrawing = true;return;}}isDrawing = true;redrawCanvas();}function draw(e) {if (!isDrawing) return;const rect = canvas.getBoundingClientRect();const mouseX = e.clientX - rect.left;const mouseY = e.clientY - rect.top;redrawCanvas();if (currentTool === 'select' && selectedElement) {// 移动选中的元素const dx = mouseX - startX;const dy = mouseY - startY;selectedElement.x += dx;selectedElement.y += dy;startX = mouseX;startY = mouseY;redrawCanvas();return;}// 绘制预览ctx.strokeStyle = '#999';ctx.lineWidth = 2;ctx.setLineDash([5, 5]);switch(currentTool) {case 'bond':ctx.beginPath();ctx.moveTo(startX, startY);ctx.lineTo(mouseX, mouseY);ctx.stroke();break;case 'double-bond':drawDoubleBond(startX, startY, mouseX, mouseY, true);break;case 'triple-bond':drawTripleBond(startX, startY, mouseX, mouseY, true);break;case 'wedge':drawWedgeBond(startX, startY, mouseX, mouseY, true);break;case 'dash':drawDashBond(startX, startY, mouseX, mouseY, true);break;}ctx.setLineDash([]);}function stopDrawing(e) {if (!isDrawing) return;const rect = canvas.getBoundingClientRect();const endX = e.clientX - rect.left;const endY = e.clientY - rect.top;if (currentTool === 'select') {isDrawing = false;selectedElement = null;return;}// 只添加元素如果移动了足够的距离if (Math.abs(endX - startX) > 5 || Math.abs(endY - startY) > 5) {switch(currentTool) {case 'bond':elements.push({type: 'bond',x1: startX,y1: startY,x2: endX,y2: endY,width: 2});break;case 'double-bond':elements.push({type: 'double-bond',x1: startX,y1: startY,x2: endX,y2: endY,width: 2});break;case 'triple-bond':elements.push({type: 'triple-bond',x1: startX,y1: startY,x2: endX,y2: endY,width: 2});break;case 'wedge':elements.push({type: 'wedge',x1: startX,y1: startY,x2: endX,y2: endY,width: 8});break;case 'dash':elements.push({type: 'dash',x1: startX,y1: startY,x2: endX,y2: endY,width: 2});break;case 'text':const text = prompt('输入原子符号或文本:', 'C');if (text) {elements.push({type: 'text',text: text,x: startX,y: startY,fontSize: 16});}break;}}isDrawing = false;redrawCanvas();}function redrawCanvas() {ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制所有元素elements.forEach(element => {switch(element.type) {case 'bond':drawBond(element.x1, element.y1, element.x2, element.y2, element.width);break;case 'double-bond':drawDoubleBond(element.x1, element.y1, element.x2, element.y2);break;case 'triple-bond':drawTripleBond(element.x1, element.y1, element.x2, element.y2);break;case 'wedge':drawWedgeBond(element.x1, element.y1, element.x2, element.y2);break;case 'dash':drawDashBond(element.x1, element.y1, element.x2, element.y2);break;case 'text':drawText(element.text, element.x, element.y, element.fontSize);break;}});// 高亮选中的元素if (selectedElement) {ctx.strokeStyle = '#4285F4';ctx.lineWidth = 2;ctx.setLineDash([3, 3]);switch(selectedElement.type) {case 'bond':case 'double-bond':case 'triple-bond':case 'wedge':case 'dash':ctx.beginPath();ctx.moveTo(selectedElement.x1, selectedElement.y1);ctx.lineTo(selectedElement.x2, selectedElement.y2);ctx.stroke();break;case 'text':ctx.strokeRect(selectedElement.x - 5, selectedElement.y - selectedElement.fontSize, ctx.measureText(selectedElement.text).width + 10, selectedElement.fontSize + 5);break;}ctx.setLineDash([]);}}// 绘制单键function drawBond(x1, y1, x2, y2, width = 2) {ctx.strokeStyle = '#000';ctx.lineWidth = width;ctx.beginPath();ctx.moveTo(x1, y1);ctx.lineTo(x2, y2);ctx.stroke();}// 绘制双键function drawDoubleBond(x1, y1, x2, y2, isPreview = false) {const angle = Math.atan2(y2 - y1, x2 - x1);const offset = isPreview ? 3 : 2;// 计算垂直方向的偏移const dx = -Math.sin(angle) * offset;const dy = Math.cos(angle) * offset;// 绘制两条平行线drawBond(x1 + dx, y1 + dy, x2 + dx, y2 + dy);drawBond(x1 - dx, y1 - dy, x2 - dx, y2 - dy);}// 绘制三键function drawTripleBond(x1, y1, x2, y2, isPreview = false) {const angle = Math.atan2(y2 - y1, x2 - x1);const offset = isPreview ? 5 : 3;// 计算垂直方向的偏移const dx = -Math.sin(angle) * offset;const dy = Math.cos(angle) * offset;// 绘制三条平行线drawBond(x1, y1, x2, y2);drawBond(x1 + dx, y1 + dy, x2 + dx, y2 + dy);drawBond(x1 - dx, y1 - dy, x2 - dx, y2 - dy);}// 绘制楔形键function drawWedgeBond(x1, y1, x2, y2, isPreview = false) {const angle = Math.atan2(y2 - y1, x2 - x1);const width = isPreview ? 8 : 6;// 计算楔形的两个端点const dx = -Math.sin(angle) * width / 2;const dy = Math.cos(angle) * width / 2;ctx.fillStyle = isPreview ? 'rgba(0, 0, 0, 0.3)' : '#000';ctx.beginPath();ctx.moveTo(x1, y1);ctx.lineTo(x2 + dx, y2 + dy);ctx.lineTo(x2 - dx, y2 - dy);ctx.closePath();ctx.fill();}// 绘制虚线键function drawDashBond(x1, y1, x2, y2, isPreview = false) {ctx.strokeStyle = isPreview ? 'rgba(0, 0, 0, 0.3)' : '#000';ctx.lineWidth = 2;ctx.setLineDash([5, 3]);ctx.beginPath();ctx.moveTo(x1, y1);ctx.lineTo(x2, y2);ctx.stroke();ctx.setLineDash([]);}// 绘制文本function drawText(text, x, y, fontSize = 16) {ctx.font = `${fontSize}px Arial`;ctx.fillStyle = '#000';ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.fillText(text, x, y);}// 获取指定位置的元素function getElementAtPosition(x, y) {// 首先检查文本元素for (let i = elements.length - 1; i >= 0; i--) {const element = elements[i];if (element.type === 'text') {ctx.font = `${element.fontSize}px Arial`;const textWidth = ctx.measureText(element.text).width;const textHeight = element.fontSize;if (x >= element.x - textWidth/2 - 5 && x <= element.x + textWidth/2 + 5 && y >= element.y - textHeight/2 - 5 && y <= element.y + textHeight/2 + 5) {return element;}}}// 然后检查键for (let i = elements.length - 1; i >= 0; i--) {const element = elements[i];if (element.type !== 'text') {// 计算点到线段的距离if (isPointNearLine(x, y, element.x1, element.y1, element.x2, element.y2, 8)) {return element;}}}return null;}// 检查点是否靠近线段function isPointNearLine(px, py, x1, y1, x2, y2, threshold) {// 线段长度const lineLength = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));// 计算点到线段的投影const u = ((px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)) / (lineLength * lineLength);// 如果投影在线段外,计算到端点的距离if (u < 0) {return Math.sqrt((px - x1) * (px - x1) + (py - y1) * (py - y1)) <= threshold;} else if (u > 1) {return Math.sqrt((px - x2) * (px - x2) + (py - y2) * (py - y2)) <= threshold;}// 计算投影点const projX = x1 + u * (x2 - x1);const projY = y1 + u * (y2 - y1);// 计算点到投影点的距离const distance = Math.sqrt((px - projX) * (px - projX) + (py - projY) * (py - projY));return distance <= threshold;}// 清空画布document.querySelector('[data-tool="clear"]').addEventListener('click', function() {if (confirm('确定要清空画布吗?')) {elements = [];redrawCanvas();}});// 橡皮擦工具document.querySelector('[data-tool="erase"]').addEventListener('click', function() {currentTool = 'erase';canvas.style.cursor = 'url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'16\' height=\'16\' viewBox=\'0 0 16 16\'><circle cx=\'8\' cy=\'8\' r=\'8\' fill=\'red\' opacity=\'0.5\'/></svg>") 8 8, auto';});canvas.addEventListener('click', function(e) {if (currentTool === 'erase') {const rect = canvas.getBoundingClientRect();const x = e.clientX - rect.left;const y = e.clientY - rect.top;const element = getElementAtPosition(x, y);if (element) {elements = elements.filter(el => el !== element);redrawCanvas();}}});// 在DOMContentLoaded事件监听器内添加以下代码// 预设结构
const presets = {benzene: {name: "苯环",elements: [// 六边形的六个边// { type: 'bond', x1: 200, y1: 100, x2: 250, y2: 100, width: 2 },{ type: 'bond', x1: 250, y1: 100, x2: 275, y2: 135, width: 2 },// { type: 'bond', x1: 275, y1: 135, x2: 250, y2: 170, width: 2 },{ type: 'bond', x1: 250, y1: 170, x2: 200, y2: 170, width: 2 },// { type: 'bond', x1: 200, y1: 170, x2: 175, y2: 135, width: 2 },{ type: 'bond', x1: 175, y1: 135, x2: 200, y2: 100, width: 2 },// 三个交替的双键{ type: 'double-bond', x1: 200, y1: 100, x2: 250, y2: 100, width: 2 },{ type: 'double-bond', x1: 275, y1: 135, x2: 250, y2: 170, width: 2 },{ type: 'double-bond', x1: 200, y1: 170, x2: 175, y2: 135, width: 2 },// 可选:添加圆圈表示芳香性// { type: 'aromatic-circle', cx: 225, cy: 135, radius: 30, width: 1 }]},cyclohexane: {name: "环己烷",elements: [{ type: 'bond', x1: 200, y1: 100, x2: 250, y2: 100, width: 2 },{ type: 'bond', x1: 250, y1: 100, x2: 275, y2: 140, width: 2 },{ type: 'bond', x1: 275, y1: 140, x2: 250, y2: 180, width: 2 },{ type: 'bond', x1: 250, y1: 180, x2: 200, y2: 180, width: 2 },{ type: 'bond', x1: 200, y1: 180, x2: 175, y2: 140, width: 2 },{ type: 'bond', x1: 175, y1: 140, x2: 200, y2: 100, width: 2 }]},cyclopentane: {name: "环戊烷",elements: [{ type: 'bond', x1: 200, y1: 100, x2: 240, y2: 100, width: 2 },{ type: 'bond', x1: 240, y1: 100, x2: 260, y2: 130, width: 2 },{ type: 'bond', x1: 260, y1: 130, x2: 220, y2: 160, width: 2 },{ type: 'bond', x1: 220, y1: 160, x2: 180, y2: 130, width: 2 },{ type: 'bond', x1: 180, y1: 130, x2: 200, y2: 100, width: 2 }]},methane: {name: "甲烷",elements: [{ type: 'bond', x1: 200, y1: 100, x2: 200, y2: 150, width: 2 },{ type: 'bond', x1: 200, y1: 150, x2: 180, y2: 180, width: 2 },{ type: 'bond', x1: 200, y1: 150, x2: 220, y2: 180, width: 2 },{ type: 'wedge', x1: 200, y1: 150, x2: 190, y2: 120, width: 6 },{ type: 'dash', x1: 200, y1: 150, x2: 210, y2: 120, width: 2 }]},ethane: {name: "乙烷",elements: [{ type: 'bond', x1: 150, y1: 150, x2: 200, y2: 150, width: 2 },{ type: 'bond', x1: 200, y1: 150, x2: 250, y2: 150, width: 2 },{ type: 'bond', x1: 150, y1: 150, x2: 130, y2: 180, width: 2 },{ type: 'bond', x1: 150, y1: 150, x2: 170, y2: 180, width: 2 },{ type: 'bond', x1: 250, y1: 150, x2: 230, y2: 180, width: 2 },{ type: 'bond', x1: 250, y1: 150, x2: 270, y2: 180, width: 2 }]},ethene: {name: "乙烯",elements: [{ type: 'bond', x1: 150, y1: 150, x2: 200, y2: 150, width: 2 },{ type: 'double-bond', x1: 200, y1: 150, x2: 250, y2: 150, width: 2 },{ type: 'bond', x1: 150, y1: 150, x2: 150, y2: 180, width: 2 },{ type: 'bond', x1: 250, y1: 150, x2: 250, y2: 180, width: 2 }]},ethyne: {name: "乙炔",elements: [{ type: 'bond', x1: 150, y1: 150, x2: 200, y2: 150, width: 2 },{ type: 'triple-bond', x1: 200, y1: 150, x2: 250, y2: 150, width: 2 }]}
};// 预设按钮点击事件
document.querySelectorAll('.preset-btn').forEach(btn => {btn.addEventListener('click', function() {const presetName = this.dataset.preset;if (presets[presetName]) {elements = JSON.parse(JSON.stringify(presets[presetName].elements));redrawCanvas();statusDiv.textContent = `已加载预设: ${presets[presetName].name}`;}});
});// 导出PNG
document.getElementById('export-png').addEventListener('click', function() {const dataURL = canvas.toDataURL('image/png');const link = document.createElement('a');link.download = 'chemical-structure.png';link.href = dataURL;link.click();
});// 导出SVG
document.getElementById('export-svg').addEventListener('click', function() {const svgData = generateSVG();const blob = new Blob([svgData], {type: 'image/svg+xml'});const url = URL.createObjectURL(blob);const link = document.createElement('a');link.download = 'chemical-structure.svg';link.href = url;link.click();
});// 复制到剪贴板
document.getElementById('copy-clipboard').addEventListener('click', function() {canvas.toBlob(function(blob) {navigator.clipboard.write([new ClipboardItem({'image/png': blob})]).then(() => {statusDiv.textContent = '图像已复制到剪贴板';}).catch(err => {statusDiv.textContent = '复制失败: ' + err;});});
});// 生成SVG
function generateSVG() {const width = canvas.width;const height = canvas.height;let svg = `<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect width="100%" height="100%" fill="white"/>
`;elements.forEach(element => {switch(element.type) {case 'bond':svg += ` <line x1="${element.x1}" y1="${element.y1}" x2="${element.x2}" y2="${element.y2}" stroke="black" stroke-width="${element.width}"/>\n`;break;case 'double-bond':const angle1 = Math.atan2(element.y2 - element.y1, element.x2 - element.x1);const dx1 = -Math.sin(angle1) * 2;const dy1 = Math.cos(angle1) * 2;svg += ` <line x1="${element.x1 + dx1}" y1="${element.y1 + dy1}" x2="${element.x2 + dx1}" y2="${element.y2 + dy1}" stroke="black" stroke-width="${element.width}"/>\n`;svg += ` <line x1="${element.x1 - dx1}" y1="${element.y1 - dy1}" x2="${element.x2 - dx1}" y2="${element.y2 - dy1}" stroke="black" stroke-width="${element.width}"/>\n`;break;case 'triple-bond':const angle2 = Math.atan2(element.y2 - element.y1, element.x2 - element.x1);const dx2 = -Math.sin(angle2) * 3;const dy2 = Math.cos(angle2) * 3;svg += ` <line x1="${element.x1}" y1="${element.y1}" x2="${element.x2}" y2="${element.y2}" stroke="black" stroke-width="${element.width}"/>\n`;svg += ` <line x1="${element.x1 + dx2}" y1="${element.y1 + dy2}" x2="${element.x2 + dx2}" y2="${element.y2 + dy2}" stroke="black" stroke-width="${element.width}"/>\n`;svg += ` <line x1="${element.x1 - dx2}" y1="${element.y1 - dy2}" x2="${element.x2 - dx2}" y2="${element.y2 - dy2}" stroke="black" stroke-width="${element.width}"/>\n`;break;case 'wedge':const angle3 = Math.atan2(element.y2 - element.y1, element.x2 - element.x1);const dx3 = -Math.sin(angle3) * element.width / 2;const dy3 = Math.cos(angle3) * element.width / 2;svg += ` <path d="M${element.x1},${element.y1} L${element.x2 + dx3},${element.y2 + dy3} L${element.x2 - dx3},${element.y2 - dy3} Z" fill="black"/>\n`;break;case 'dash':svg += ` <line x1="${element.x1}" y1="${element.y1}" x2="${element.x2}" y2="${element.y2}" stroke="black" stroke-width="${element.width}" stroke-dasharray="5,3"/>\n`;break;case 'text':svg += ` <text x="${element.x}" y="${element.y}" font-family="Arial" font-size="${element.fontSize}" text-anchor="middle" dominant-baseline="middle">${element.text}</text>\n`;break;}});svg += '</svg>';return svg;
}// 初始化redrawCanvas();
});
功能说明
这个化学键线式编辑器提供以下功能:
-
基本工具:
- 选择工具:选择和移动已有元素
- 单键、双键、三键工具
- 楔形键(实心三角形)和虚线键工具
- 文本工具:添加原子符号或注释
- 橡皮擦工具:删除元素
- 清空画布
-
交互功能:
- 点击拖动绘制化学键
- 选择并移动已有元素
- 点击删除元素
- 实时预览绘制效果
-
化学键表示:
- 正确绘制不同类型的化学键
- 楔形键表示立体化学
- 虚线键表示远离观察者的键
相关文章:
deepseek v3-0324 化学键线式Canvas编辑器设计
化学键线式Canvas编辑器设计 下面是一个基于HTML5 Canvas的化学键线式编辑器的基本实现方案。这个编辑器允许用户绘制有机化学中常见的键线式结构。 基本HTML结构 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"…...
解决 CMS Old GC 频繁触发线上问题技术方案
目录 一、CMS GC 工作原理 二、现象分析 (一)具体表现说明 (二)触发条件 三、总结优化措施 (一)调整 CMS 启动条件:降低 Old 区触发阈值 1. 原理分析 2. 建议配置 (二&…...
后端实现加解密工具类(记录)
后端利用3DES加解密工具类实现特殊字段加解密,比如个人信息、请求参数等 ,可以自定义密钥和IV加密,代码如下,直接使用即可。 import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory…...
云原生技术赋能企业数字化转型:实战案例与架构演进
引言:数字化转型的云原生机遇 在VUCA时代背景下,某金融科技企业面临系统扩展性差、运维成本高企的困境。通过采用云原生技术栈,6个月内实现资源利用率提升300%,故障恢复时间从小时级缩短至分钟级。本文将深度解析该企业技术演进路…...
驱动开发系列49 - 搭建 Vulkan 驱动调试环境(编译 mesa 3D)- Ubuntu24.04
一:搭建Vulkan运行环境 安装vulkan依赖包: 1. sudo apt install vulkan-tools 2. sudo apt install libvulkan-dev 3. sudo apt install vulkan-utility-libraries-dev spirv-tools 4. sudo apt install libglfw3-dev libglm-dev 5. sudo apt install libxxf86vm-dev libxi-…...
自然语言处理(26:(终章Attention 2.)带Attention的seq2seq的实现)
系列文章目录 终章 1:Attention的结构 终章 2:带Attention的seq2seq的实现 终章 3:Attention的评价 终章 4:关于Attention的其他话题 终章 5:Attention的应用 目录 系列文章目录 前言 一、编码器的实现 二、解…...
Qt5.14.2+mingw64编译OpenCV3.4.14一次成功记录
上一文中编译opencv4.5成功了,但是使用过程中没有成功,网上很多的代码没法跑起来,所以才有了此文来编译一个低版本的opencv3的过程记录,全程截图。 一、软件安装 1.1 Python3.8版本安装路径:C:\Users\Administrator\AppData\Loca…...
【数据库原理】基础篇:MySQL基础入门与实战指南
前言 在当今数字化时代,数据已成为企业运营的核心资产之一。而MySQL作为一款广泛使用的开源关系型数据库管理系统,凭借其高性能、可靠性和易用性,成为众多开发者和企业的首选。本文将从MySQL的基础概念出发,逐步深入到实际操作&a…...
使用Python解析PPT文件并生成JSON结构详解
引言 PowerPoint(PPT)文件的自动化处理是办公自动化和数据提取的常见需求。本文将介绍如何通过Python的python-pptx库,将PPT文件的样式、结构、文本内容等信息解析为标准化的JSON格式,为后续的自动化处理、数据迁移或样式复用提供…...
C#:第一性原理拆解属性(property)
目录 第一步:从最基本的需求出发 第二步:引入控制需求 第三步:优化访问方式 第四步:剖析属性的本质 第五步:进一步简化和演化 自动属性的定义和作用 自动属性的特点和限制 第六步:总结属性的第一性…...
nacos 2.x使用java语言实现自定义Loadbalance
一、核心实现思路 Nacos 2.x 的负载均衡自定义支持两种模式: 基于 Ribbon 的兼容方案(适用于 Spring Cloud 2020 之前版本)基于 Spring Cloud LoadBalancer 的方案(推荐,适配最新 Spring Cloud 2023 和 Nacos 2.x&am…...
torch.nn.Conv2d介绍——Pytorch中的二维卷积层
torch.nn.Conv2d是torch.nn模块中的二维卷积层类,用于构建神经网络中的二维卷积层。 1、基本语法 torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride1, padding0, dilation1, groups1, biasTrue, padding_modezeros, deviceNone, dtypeNone)将 2D …...
ubuntu虚拟机裁剪img文件系统
1. 定制文件系统前期准备 将rootfs.img文件准备好,并创建target文件夹2. 挂载文件系统 sudo mount rootfs.img target #挂载文件系统 sudo chroot target #进入chroot环境3. 内裁剪文件系统 增删裁剪文件系统 exit #退出chroot环境 sudo umount target…...
一文详细讲解Python(详细版一篇学会Python基础和网络安全)
引言 在当今数字化时代,Python 作为一种简洁高效且功能强大的编程语言,广泛应用于各个领域,从数据科学、人工智能到网络安全等,都能看到 Python 的身影。而网络安全作为保障信息系统和数据安全的关键领域,其重要性不言…...
使用QT调试LidarView
前段时间使用VeloView想进行点云的显示,后来发现VeloView的尺子测距不好用,也没有筛选点的功能,就放弃了。kitware同家的还有LidarView,功能多一些,更新的时间更晚,而且还兼容速腾、禾赛等多家点云设备可以…...
JAVA:使用 Curator 进行 ZooKeeper 操作的技术指南
1、简述 Apache Curator 是一个基于 ZooKeeper 的 Java 客户端库,它极大地简化了使用 ZooKeeper 的开发工作。Curator 提供了高层次的 API,封装了很多复杂的 ZooKeeper 操作,例如连接管理、分布式锁、Leader 选举等。 在分布式系统中&#…...
【SpringCloud】LoadBalance-负载均衡
4. 负载均衡-LoadBalance 4.1 为什么需要负载均衡? 不知道各位心中有没有女神,通常来说一个女神就会有多个舔狗,那这些舔狗呢,就会心甘情愿的帮女神干活,假设女神小美现在有三个舔狗,小美喜欢让这三个舔狗…...
[250401] OpenAI 向免费用户开放 GPT-4o 图像生成功能 | Neovim 0.11 新特性解读
目录 OpenAI 向免费用户开放 GPT-4o 图像生成功能Neovim 0.11 新特性解读更简化的 LSP 设置和配置内置自动补全改进的悬停文档诊断信息增强更多默认键映射终端模拟器改进其他改进 OpenAI 向免费用户开放 GPT-4o 图像生成功能 2025年4月1日早上,OpenAI CEO Sam Altm…...
VBA数据库解决方案第二十讲:SQL在VBA中几种常见的表达方式
《VBA数据库解决方案》教程(版权10090845)是我推出的第二套教程,目前已经是第二版修订了。这套教程定位于中级,是学完字典后的另一个专题讲解。数据库是数据处理的利器,教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…...
SAIL-RK3588J 核心板技术方案——高精度装配式建筑机器人控制
(本方案契合《建筑机器人产业目录》政策要求) 一、方案背景与政策支持 政策驱动 2025年2月《建筑机器人产业目录》明确将“高精度建筑机器人控制设备”纳入重点补贴范围,要求定位精度≤0.5mm、支持实时质检与多机协同,…...
人工智能在生物医药领域的应用地图:AIBC2025将于6月在上海召开!
人工智能在生物医药领域的应用地图:AIBC2025将于6月在上海召开! 近年来,人工智能在生物医药行业中的应用受到广泛关注。 2024年10月,2024诺贝尔化学奖被授予“计算蛋白质设计和蛋白质结构预测”,这为行业从业人员带来…...
C#高级:利用LINQ进行实体列表的集合运算
问题引入: Teacher实体的唯一标识符是Name和Classes字段(或者说这两个字段唯一确定一条数据),如何对两个实体列表做交集、差集运算呢?(并集直接调用AddRange方法即可) 一、重写方法实现 1.原…...
Python项目-基于Flask的个人博客系统设计与实现(2)
源代码 续 {% extends base.html %}{% block title %}评论管理{% endblock %}{% block content %} <div class"container py-4"><div class"row"><div class"col-md-3"><div class"list-group mb-4"><a h…...
2023第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(真题题解)(C++/Java题解)
记录刷题的过程、感悟、题解。 希望能帮到,那些与我一同前行的,来自远方的朋友😉 大纲: 1、日期统计-(解析)-暴力dfs(😉蓝桥专属 2、01串的熵-(解析)-不要chu…...
前端界面在线excel编辑器 。node编写post接口获取文件流,使用传参替换表格内容展示、前后端一把梭。
首先luckysheet插件是支持在线替换excel内容编辑得但是浏览器无法调用本地文件,如果只是展示,让后端返回文件得二进制文件流就可以了,直接使用luckysheet展示。 这里我们使用xlsx-populate得node简单应用来调用本地文件,自己写一个…...
在 Fedora 系统下备份远程 Windows SQL Server 数据库的完整方案
一、环境准备与工具安装 1. 安装 Microsoft SQL Server 命令行工具 Fedora 需安装 mssql-tools 和 ODBC 驱动: # 添加 Microsoft 仓库 sudo curl -o /etc/yum.repos.d/msprod.repo https://packages.microsoft.com/config/rhel/8/prod.repo# 安装工具包 …...
从24GHz到71GHz:Sivers半导体的广泛频率范围5G毫米波产品解析
在5G技术的浪潮中,Sivers半导体推出了创新的毫米波无线产品,为通信行业带来高效、可靠的解决方案。这些产品支持从24GHz到71GHz的频率,覆盖许可与非许可频段,适应高速、低延迟的通信场景。 5G通信频段的一点事儿及Sivers毫米波射频…...
从【抖音安全与信任中心】观察企业如何做算法透明
抖音主动公开算法原理树立行业新标杆: “抖音安全与信任中心”网站(95152.douyin.com) 1 算法透明的几点准则 需涵盖技术逻辑公开、治理机制可查、用户参与共建等维度。以下是基于抖音案例总结的可行路径,以及几个准则࿱…...
html处理Base文件流
处理步骤 从服务返回的字符串中提取文件流数据,可能是Base64或二进制。将数据转换为Blob对象。创建对象URL。创建<a>元素,设置href和download属性。触发点击事件以下载文件。删除缓存数据 代码 // 假设这是从服务返回的Base64字符串(…...
MySQL内存管理机制详解
目录标题 MySQL内存管理机制详解1. **内存组成与核心组件**2. **RSS与共享内存的关系**3. **OOM问题排查步骤**4. **典型案例** Buffer Pool(缓冲池) 确实属于共享内存(Shared Memory)的核心组成部分?1. **Buffer Pool…...
《算法笔记》9.7小节——数据结构专题(2)->堆 问题 C: 合并果子(堆)
题目描述 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。 每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,…...
化繁为简解决leetcode第1289题下降路径最小和II
1289.下降路径最小和II 难度:困难 问题描述: 给你一个nxn整数矩阵grid,请你返回非零偏移下降路径数字和的最小值。 非零偏移下降路径定义为:从grid数组中的每一行选择一个数字,且按顺序选出来的数字中,…...
蓝桥杯省模拟赛 数位和
问题描述 只能被 1 和本身整除的数称为质数。 请问在 1 (含)到 1000000 (含)中,有多少个质数的各个数位上的数字之和为 2323 。 提示:599 就是这样一个质数,各个数位上的数字之和为 59923 。…...
MySQL和Oracle批量插入SQL差异详解
文章目录 MySQL和Oracle批量插入SQL差异详解1. 基本批量插入语法1.1 MySQL批量插入1.2 Oracle批量插入 2. 带序列的批量插入2.1 MySQL带自增ID的批量插入2.2 Oracle带序列的批量插入 3. 条件批量插入3.1 MySQL条件批量插入3.2 Oracle条件批量插入 MySQL和Oracle批量插入SQL差异…...
YOLOv5配置训练以及华为昇腾910B推理
参考文章: 保姆式yolov5教程,训练你自己的数据集 - 知乎 Windows 10|11下安装mmyolo-0.5.0版本 - 知乎 Ubuntu22.04安装教程&基于华为Ascend AI处理器的om模型atc转换环境安装_ubuntu安装atc工具-CSDN博客嵌入式AI---在华为昇腾推理自己的yolov5目标…...
Visual Studio Code配置自动规范代码格式
目录 前言1. 插件安装2. 配置个性化设置2.1 在左下角点击设置按钮 ,点击命令面板(或者也可以之间按快捷键CtrlShiftP)2.2 在弹出的搜索框输入 settings.json,打开首选项:打开工作区设置;2.3 在settings.jso…...
【网安面经合集】42 道高频 Web 安全面试题全解析(附原理+防御+思路)
对于正在准备 安全岗求职或实习的同学们来说,Web 安全面试题几乎是必问项。 尤其是一些经常出现的考点,比如 SQL 注入、XSS、CSRF、反序列化、逻辑漏洞、WAF 绕过等等,不仅需要你知道“是什么”,还得能“讲清楚原理、分类、修复和…...
论文笔记(七十五)Auto-Encoding Variational Bayes
Auto-Encoding Variational Bayes 文章概括摘要1 引言2 方法2.1 问题场景2.2 变分下界2.3 SGVB估计器与AEVB算法2.4 重参数化技巧 3 示例:变分自编码器(Variational Auto-Encoder)4 相关工作5 实验6 结论7 未来工作 文章概括 引用࿱…...
前端学习记录之HTML
1. 网页 1.1 什么是网页 网站是指在因特网上根据一定的规则,使用HTML等制作的用于展示特定内容相关的网页集合。 网页是网站中的一“页”,通常是HTML格式的文件,它要通过浏览器来阅读 网页是构成网站的基本元素。它通常由图片,…...
程序化广告行业(39/89):广告投放的数据分析与优化秘籍
程序化广告行业(39/89):广告投放的数据分析与优化秘籍 在程序化广告的领域中,数据分析与优化调整是实现精准投放、提升广告效果的核心环节。作为一名热衷于探索程序化广告的学习者,我希望通过这篇博客,和大…...
蓝桥杯 01游戏
问题描述 小蓝最近玩上了 01 游戏,这是一款带有二进制思想的棋子游戏。 游戏在一个大小为 N N 的棋盘上进行。棋盘上的每个位置都需要放置一个数字 0 或 1。初始情况下,棋盘上有一部分位置已经放置了固定的数字,玩家不可以更改这些位置。其…...
NoSQL 数据库的适用场景与局限性分析
NoSQL(Not Only SQL)数据库是一类非关系型数据库,通过灵活的数据模型和分布式架构解决传统关系型数据库在扩展性、性能和数据多样性上的瓶颈。以下从技术特性、适用场景、不适用场景及行业实践展开分析: 一、NoSQL数据库的核心技术特性 四大数据模型 文档型:以JSON/BSON格…...
个人网站:基于html、css、js网页开发界面
1、注册 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>注册页面</title><link rel&qu…...
嵌入式图像采集与显示系统实战详解:基于V4L2与Framebuffer的实现
在嵌入式Linux开发中,图像采集与显示是非常典型的一类应用场景。本文将基于 ARM9(S3C2410) 平台,深入讲解如何使用 V4L2 框架从 USB 摄像头采集图像数据,并通过 Framebuffer 接口实时显示到 LCD 屏幕。内容涵盖驱动架构…...
庙算兵棋推演AI开发初探(6-神经网络开发)
碎碎念: 老师让我和同学组队参加10月底截止报名的庙算比赛,我俩走运进了64强,打的过程中发现了一个重要问题——为什么别人总能打我,但是我都看不见!就像玩dota被对面英雄莫名其妙单杀了但是他就一直隐身我都不知道怎…...
嵌入式硬件篇---嘉立创PCB绘制
文章目录 前言一、PCB绘制简介1.1绘制步骤1.1.1前期准备1.1.2原理图设计1.1.3原理图转PCB1.1.4PCB布局1.1.5布线1.1.6布线优化和丝印1.1.7制版 1.2原理1.2.1电气连接原理1.2.2信号传输原理1.2.3电源和接地原理 1.3注意事项1.3.1元件封装1.3.2布局规则1.3.3过孔设计1.3.4DRC检查…...
AI与.NET技术实操系列(四):使用 Semantic Kernel 和 DeepSeek 构建AI应用
1. 引言 在人工智能技术飞速发展的今天,大型语言模型(Large Language Models, LLMs)已成为智能应用开发的核心驱动力。从智能客服到自动化内容生成,LLMs的应用正在深刻改变我们的工作和生活方式。 对于.NET开发者而言,…...
Vue 组件 - Slot 内容分发
Vue 渐进式JavaScript 框架 基于Vue2的学习笔记 - Vue组件 - Slot 内容分发 目录 Slot内容分发 旧版slot 单插槽 使用插槽 具名插槽 插槽实现导航 使用插槽优点 新版slot Or 插槽版抽屉 总结 Slot内容分发 混合父组件的内容和子组件自己模板 -- 内容分发 父组件模…...
Mysql之事务(下)
🏝️专栏:Mysql_猫咪-9527的博客-CSDN博客 🌅主页:猫咪-9527-CSDN博客 “欲穷千里目,更上一层楼。会当凌绝顶,一览众山小。” 目录 5. 事务的隔离级别与并发控制 5.1事务的隔离级别 5.2查看与设置事务的…...
LabVIEW液压控制系统开发要点
液压控制系统开发需兼顾高实时性、强抗干扰性和安全性,尤其在重工业场景中,毫秒级响应延迟或数据异常都可能导致设备损坏。本文以某钢厂液压升降平台项目为例,从硬件选型、控制算法、安全机制三方面,详解LabVIEW开发中的关键问题与…...