基于cornerstone3D的dicom影像浏览器 第二十九章 自定义菜单组件

news2025/6/7 15:33:06

文章目录

  • 前言
  • 一、程序结构
    • 1. 菜单数据结构
    • 2. XMenu.vue
    • 3. XSubMenu.vue
    • 4. XSubMenuSlot.vue
    • 5. XMenuItem.vue
  • 二、调用流程
  • 总结


前言

菜单用于组织程序功能,为用户提供导航。是用户与程序交互非常重要的接口。
开源组件库像Element Plus和Ant Design中都提供了功能强大,使用方便的菜单组件 。
本章提供一个自定义菜单组件,核心思想是调用者提供菜单数据和显示位置,就能在指定位置显示出菜单组件。
效果如下:
在这里插入图片描述


一、程序结构

一共四个组件:
XMenu.vue 主菜单
XSubMenu.vue 递归子菜单
XSubMenuSlot.vue 子菜单与菜单项插槽
XMenuItem.vue 菜单项

1. 菜单数据结构

id: String,必填
text: String,菜单项文字,必填
icon: String,菜单项最左边图标,选填
checkable: Boolean,菜单项最左边是否显示选中图标 ✓ 与check共同作用, 选填
check: Boolean,是否选中,选填
image: String,菜单项文字区图片url,选填
separate: String,菜单项分割线,值:bottom/up/both,选填
subMenu: Array,子菜单数据,选填

示例:

let menuList = ref([
	{
		id: "view",
		text: "视图",
		icon: "",
		checkable: true,
		checked: true,
		separate: "bottom"
	},
	{
		id: "edit",
		text: "编辑文字",
		icon: "icon-jawbone",
	},
	{
		id: "pseudo",
		text: "伪彩1",
		icon: "",
		image: require("@/assets/images/hot_h1.png"),
	},
	{
		id: "file",
		text: "文件",
		icon: "",
		subMenu: [
			{
				id: "open",
				text: "打开",
				icon: "",
				separate: "bottom",
			},
			{
				id: "save",
				text: "保存刚才的工作",
				icon: "icon-lungs-line",
			},
			{
				id: "close",
				text: "关闭",
				icon: "",
			},
			{
				id: "menuitem1",
				text: "菜单项1",
				icon: "",
			},
			{
				id: "menuitem2",
				text: "菜单项2",
				icon: "",
			},
			{
				id: "menuitem3",
				text: "菜单项3",
				icon: "",
			},
		],
	},

]);

显示效果:
在这里插入图片描述

2. XMenu.vue

用户入口

  1. 接受菜单数据和菜单位置
  2. 发送菜单项点击事件menuclick
  3. 自动计算菜单高度和宽度
  4. 菜单展开/收缩动画
<script lang="js" setup name="XMenu">
import { ref, computed, onMounted, reactive, h } from "vue";
import XSubMenu from "./XSubMenu.vue";
import XMenuItem from "./XMenuItem.vue";

const emit = defineEmits(["menuclick"]);
let menuList = ref([]);

const xMenu = ref(null);
const menuPos = reactive({ left: 0, top: 0 });
const ItemH = 32;
const fontSize = ref(14);
const showMenu = ref(false);

const show = (menu, pos) => {
    menuList.value = menu;
    calcMenuPos(pos);
    showMenu.value = true;
}

const calcMenuPos = (pos) => {
    const maxHeight = document.body.clientHeight;
    const maxWidth = document.body.clientWidth;
    
    if (pos.left + menuWidth.value > maxWidth) {
        menuPos.left = maxWidth - menuWidth.value;
    } else {
        menuPos.left = pos.left;
    }

    if (pos.top + menuHeight.value > maxHeight) {
        menuPos.top = pos.top2 - menuHeight.value;
    } else {
        menuPos.top = pos.top;
    }

}

const hide = () => {
    showMenu.value = false;
}

const getRect = () => {
    return xMenu.value.getBoundingClientRect();
}

const menuWidth = computed(() => {
    let w = 80;
    menuList.value.forEach((menu) => {
        const menuW = getMenuWidth(menu, fontSize.value);
        w = menuW > w ? menuW : w;
    });

    const maxW = document.body.clientWidth / 2;

    w += 40;
    const ret = w > maxW ? maxW : w;

    return ret;
});

const menuHeight = computed(() => {
    let h = ItemH * menuList.value.length;
    return h;
});

const menuStyle = computed(() => {
    return {
        width: menuWidth.value + "px",
        left: menuPos.left + "px",
        top: menuPos.top + "px",
    };
});

const getMenuWidth = (menu, fontSize) => {
    const el = document.createElement("span");
    const text = menu.text;
    el.innerText = text;
    el.style.fontSize = fontSize + "px";
    el.style.position = "absolute";
    document.body.appendChild(el);
    let w = el.offsetWidth + 50;

    if (menu.image) {
        w += 100;
    }
    document.body.removeChild(el);
    return w;
}

const hasChild = (menu) => {
    return menu.subMenu && menu.subMenu.length > 0;
}

const onMenuClick = (menu) => {
    if (menu.checkable && menu.checked !== undefined) {
        menu.checked = !menu.checked;
    }
    hide();
    emit("menuclick", menu);
}

const transBeforeEnter = (el) => {
	el.style.height = "0px";
    el.style.overflow = "hidden";
}
const transEnter = (el) => {
	el.style.height = "auto";
    const h = el.offsetHeight;
	el.style.height = "0px";
	requestAnimationFrame(() => {
		el.style.height = h + "px";
		el.style.transition = ".4s";
	});
}

const transAfterEnter = (el) => {
	el.style.transition = "initial";
     el.style.overflow = null;
}

const transBeforeLeave = (el) => {
    el.style.overflow = "hidden";
	el.style.transition = ".2s";
}
const transLeave = (el) => {
	el.style.height = "0px";
}
const transAfterLeave = (el) => {
}

defineExpose({
    show,
    hide,
    getRect
});

</script>

<template>
	<!-- <Teleport to="body"> -->
	<Transition
		@beforeEnter="transBeforeEnter"
		@enter="transEnter"
		@afterEnter="transAfterEnter"
		@before-leave="transBeforeLeave"
		@leave="transLeave"
	>
		<ul class="x-menu" ref="xMenu" v-show="showMenu" :style="menuStyle">
			<template v-for="(item, index) in menuList">
				<XSubMenu v-if="hasChild(item)" :key="item.id" :menu="item" :index="index" @menuclick="onMenuClick" />
				<XMenuItem v-else :menu="item" @click="onMenuClick(item)" />
			</template>
		</ul>
	</Transition>
	<!-- </Teleport> -->
</template>

<style lang="scss" scoped>
.x-menu {
	position: absolute;
	background-color: var(--color-theme-bg);
	color: var(--color-theme-text);
	border: 1px solid #aaa;
	z-index: 9999;
}
</style>

3. XSubMenu.vue

<script lang="js" setup name="XSubMenu">
import { ref, computed, onMounted } from "vue";
import XSubMenuSlot from "./XSubMenuSlot.vue";
import XMenuItem from "./XMenuItem.vue";

const emit = defineEmits(["menuclick"]);

const props = defineProps({
	menu: {
		type: Object,
		required: true
	},
	index: {
		type: Number,
		required: true
	}
});


const hasChild = (menu) => {
	return menu.subMenu && menu.subMenu.length > 0;
};


const onMenuClick = (menu) => {
	emit("menuclick", menu);
};
</script>

<template>
	<XSubMenuSlot :menu="menu" :index="index">
		<template #title>{{ menu.text }}</template>
		<ul>
			<template v-for="(item, index) in menu.subMenu">
				<XSubMenu v-if="hasChild(item)" :key="item.id" :menu="item" @menuclick="onMenuClick" />
				<XMenuItem v-else :key="item.id" :menu="item" @click="onMenuClick(item)" />
			</template>
		</ul>
	</XSubMenuSlot>
</template>

<style lang="scss" scoped></style>

4. XSubMenuSlot.vue

两个插槽,分别显示XMenuItem、XSubMenu
与XMenu类似:

  1. 计算子菜单宽度和高度
  2. 计算子菜单显示位置
  3. 子菜单展开/收缩动画
<script lang="js" setup name="XSubMenuSlot">
import { ref, computed, onMounted, reactive } from "vue";

const props = defineProps({
	menu: {
		type: Object,
		required: true
	},
	index: {
		type: Number,
		required: true
	}
});

const ItemH = 32;
const showMenu = ref(false);
const subMenuPos = reactive({
	left: 0,
	top: 0
});

const fontSize = ref(14);
const subMenuWidth = computed(() => {
	let w = 80;
    props.menu.subMenu.forEach((item) => {
        const menuW = getMenuWidth(item, fontSize.value);
        w = menuW > w ? menuW : w;
    });

    const maxW = document.body.clientWidth / 2;

    // menu sidebar-icon width: 40px
    w += 40;
    const ret = w > maxW ? maxW : w;

	console.log('menuWidth', ret);

    return ret;
});

const subMenuHeight = computed(() => {
	const height = ItemH * props.menu.subMenu.length;
	return height;
});


const getMenuWidth = (menu, fontSize) => {
    const el = document.createElement("span");
    const text = menu.text;
    el.innerText = text;
    el.style.fontSize = fontSize + "px";
    el.style.position = "absolute";
    document.body.appendChild(el);
    let w = el.offsetWidth + 50;

    if (menu.image) {
        w += 100;
    }
    document.body.removeChild(el);
    return w;
}

const subitemStyle = computed(() => {
	if (props.menu.separate) {
		const border = {};
		switch (props.menu.separate) {
			case "top":
				border.borderTop = "1px solid #aaa";
				break;
			case "bottom":
				border.borderBottom = "1px solid #aaa";
				break;
			case "both":
				border.borderTop = "1px solid #aaa";
				border.borderBottom = "1px solid #aaa";
				break;
		}
		return border;
	}
});

const subMenuStyle = computed(() => {
	return {
		left: subMenuPos.left + "px",
		top: subMenuPos.top + "px",
		width: subMenuWidth.value + "px"
	}
});

const show = (e) => {
	showMenu.value = true;
	const el = e.currentTarget;
	calcSubMenuPos(el);
}

const calcSubMenuPos = (el) => {
	const maxWidth = document.body.clientWidth;
	const maxHeight = document.body.clientHeight;

    const rect = el.getBoundingClientRect();

	const xEnd = rect.right + subMenuWidth.value;
	const yEnd = rect.y + props.index*ItemH + subMenuHeight.value;

	if (xEnd > maxWidth) {
		subMenuPos.left = 0 - subMenuWidth.value;
	} else {
		subMenuPos.left = rect.width;
	}

	if (yEnd > maxHeight) {
		subMenuPos.top = ItemH - subMenuHeight.value;
	} else {
		subMenuPos.top = 0;
	}

}

const hide = (e) => {
	showMenu.value = false;
}

const transBeforeEnter = (el) => {
	el.style.height = "0px";
    el.style.overflow = "hidden";
}
const transEnter = (el) => {
	el.style.height = "auto";
	const h = el.offsetHeight;
	el.style.height = "0px";
	requestAnimationFrame(() => {
		el.style.height = h + "px";
		el.style.transition = ".4s";
	});
}

const transAfterEnter = (el) => {
	el.style.transition = "initial";
     el.style.overflow = null;
}

const transBeforeLeave = (el) => {
    el.style.overflow = "hidden";
	el.style.transition = ".2s";
}
const transLeave = (el) => {
	el.style.height = "0px";
}
const transAfterLeave = (el) => {
}
</script>

<template>
	<div class="container" @mouseenter="show" @mouseleave="hide">
		<li class="subitem" :style="subitemStyle">
			<span class="subitem-bar"></span>
			<span class="subitem-text">
				<slot name="title"></slot>
			</span>
			<div class="subitem-right">
				<span class="subitem-right-icon"></span>
			</div>
		</li>
		<Transition
			@beforeEnter="transBeforeEnter"
			@enter="transEnter"
			@afterEnter="transAfterEnter"
			@before-leave="transBeforeLeave"
			@leave="transLeave"
		>
			<div class="submenu" v-show="showMenu" :style="subMenuStyle">
				<slot></slot>
			</div>
		</Transition>
	</div>
</template>

<style lang="scss" scoped>
.container {
	position: relative;
}
.submenu {
	position: absolute;
	border: 1px solid #aaa;
}

.subitem {
	display: flex;
	flex-direction: row;
	width: 100%;
	height: 32px;
	background-color: #fdfdfd;
	background-color: var(--color-menu-bg);
	z-index: 9999;
	overflow: hidden;
}

.subitem-bar {
	width: 38px;
	height: 100%;
	background-color: var(--color-menu-bar);
	fill: var(--color-theme-text);
}

.subitem-text {
	flex: 1;
	height: 32px;
	line-height: 32px;
	font-size: 16px;
	padding-left: 10px;
	cursor: default;
	user-select: none;
	-webkit-user-select: none; /* Safari */
	-moz-user-select: none; /* Firefox */
	-ms-user-select: none; /* IE 10 and IE 11 */
}

.subitem-right {
	width: 30px;
	height: 100%;
	padding-right: 6px;
}

.subitem-right-icon {
	float: right;
	width: 16px;
	height: 32px;
	background: url(../../assets/images/arrow_right.png) no-repeat center center;
	background-size: 16px auto;
}

.subitem:hover {
	background-color: lightblue;
	color: blue;
	border: 1px solid lightskyblue;
}
</style>

5. XMenuItem.vue

菜单项,显示icon, text, image, separate

<script lang="js" setup name="XMenuItem">
import { ref, computed, onMounted } from "vue";
import SvgIcon from "../SvgIcon.vue";

const props = defineProps({
	menu: {
		type: Object,
		required: true
	}
});

const emit = defineEmits(["menuclick"]);

const menuItemStyle = computed(() => {
	if (props.menu.separate) {
		const border = {};
		switch (props.menu.separate) {
			case "top":
				border.borderTop = "1px solid #aaa";
				break;
			case "bottom":
				border.borderBottom = "1px solid #aaa";
				break;
			case "both":
				border.borderTop = "1px solid #aaa";
				border.borderBottom = "1px solid #aaa";
				break;
		}
		return border;
	}
});

const iconStyle = computed(() => {
	if (props.menu.checkable) {
		return {
			backgroundImage: props.menu.checked
				? `url("src/assets/images/choose.png")`
				: "",
		};
	} else {
		return {
			backgroundImage: props.menu.icon,
		};
	}
});
</script>

<template>
	<li class="menuitem" :style="menuItemStyle">
		<div class="menuitem-bar">
			<svg-icon v-if="menu.icon" class="menuitem-bar__icon" :icon="menu.icon" size="28px" />
			<div v-else class="menuitem-bar__icon" :style="iconStyle"></div>
		</div>
		<div class="menuitem-text">{{ menu.text }}</div>
		<img v-if="menu.image" class="menuitem-image" :src="menu.image" />
	</li>
</template>

<style lang="scss" scoped>
.menuitem {
	display: flex;
	flex-direction: row;
	align-items: center;
	height: 32px;
	background-color: var(--color-menu-bg);
	z-index: 9999;
	overflow: hidden;
}

.menuitem-bar {
	display: flex;
	flex-direction: row;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 100%;
	background-color: var(--color-menu-bar);
}

.menuitem-bar__icon {
	width: 38px;
	height: 100%;
	background-repeat: no-repeat;
	background-position: center center;
	background-size: 24px auto;
	fill: var(--color-theme-text);
}

.menuitem-text {
	line-height: 32px;
	font-size: 16px;
	padding-left: 10px;
	cursor: default;
	user-select: none;
	-webkit-user-select: none; /* Safari */
	-moz-user-select: none; /* Firefox */
	-ms-user-select: none; /* IE 10 and IE 11 */
}

.menuitem-image {
	margin-left: 8px;
}

.menuitem:hover {
	background-color: lightblue;
	color: blue;
	border: 1px solid lightskyblue;
}
</style>

二、调用流程

  1. 导入XMenu.vue
  2. 在模板中添加XMenu
  3. 绑定变量
  4. 定义菜单数据
  5. 调用show函数
import XMenu from "./XMenu/XMenu.vue";

const xMenu = ref(null);

const menuList = ref([
	{
		id: "view",
		text: "视图",
		icon: "",
		checkable: true,
		checked: true,
		separate: "bottom"
	},
	{
		id: "edit",
		text: "编辑文字",
		icon: "icon-jawbone",
	},
	{
		id: "pseudo",
		text: "伪彩1",
		icon: "",
		image: require("@/assets/images/hot_h1.png"),
	},
	{
		id: "file",
		text: "文件",
		icon: "",
		subMenu: [
			{
				id: "open",
				text: "打开",
				icon: "",
				separate: "bottom",
			},
			{
				id: "save",
				text: "保存刚才的工作",
				icon: "icon-lungs-line",
			},
			{
				id: "close",
				text: "关闭",
				icon: "",
			},
			{
				id: "menuitem1",
				text: "菜单项1",
				icon: "",
			},
			{
				id: "menuitem2",
				text: "菜单项2",
				icon: "",
			},
			{
				id: "menuitem3",
				text: "菜单项3",
				icon: "",
			},
		],
	},

]);

const showMenu = (e) => {
	xMenu.value.show(menuList.value, { left: e.clientX, top: e.clientY})
}

const hideMenu = () => {
	xMenu.value.hide();
}

<template>
     <div class="toolbar">
        <XMenu ref="xMenu" @mouseleave="hideMenu" />
        ...
		<div class="toolbar-row">
			<el-button @click="showMenu">菜单2</el-button>
			<el-button @click="dcmtag">DICOM标签</el-button>
			<el-button @click="mprvr">MPR+VR</el-button>
			<el-button @click="showMenu">菜单3</el-button>
		</div>
     	...
     </div>
</template>

总结

本章实现自定义菜单组件,支持图标、分隔线、选中图标、文字区图片、子菜单、展开/收缩动画。如需要显示更复杂内容,可自行扩展XMenuItem.vue
调用方便,只需要提供菜单数据和菜单显示位置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2403060.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Block总结】DBlock,结合膨胀空间注意模块(Di-SpAM)和频域模块Gated-FFN|即插即用|CVPR2025

论文信息 标题: DarkIR: Robust Low-Light Image Restoration 作者: Daniel Feijoo, Juan C. Benito, Alvaro Garcia, Marcos Conde 论文链接&#xff1a;https://arxiv.org/pdf/2412.13443 GitHub链接&#xff1a;https://github.com/cidautai/DarkIR 创新点 DarkIR提出了…

口罩佩戴检测算法AI智能分析网关V4工厂/工业等多场景守护公共卫生安全

一、引言​ 在公共卫生安全日益受到重视的当下&#xff0c;口罩佩戴成为预防病毒传播、保障人员健康的重要措施。为了高效、精准地实现对人员口罩佩戴情况的监测&#xff0c;AI智能分析网关V4口罩检测方案应运而生。该方案依托先进的人工智能技术与强大的硬件性能&#xff0c;…

Double/Debiased Machine Learning

独立同步分布的观测数据 { W i ( Y i , D i , X i ) ∣ i ∈ { 1 , . . . , n } } \{W_i(Y_i,D_i,X_i)| i\in \{1,...,n\}\} {Wi​(Yi​,Di​,Xi​)∣i∈{1,...,n}}&#xff0c;其中 Y i Y_i Yi​表示结果变量&#xff0c; D i D_i Di​表示因变量&#xff0c; X i X_i Xi​表…

HarmonyOS Next 弹窗系列教程(4)

HarmonyOS Next 弹窗系列教程&#xff08;4&#xff09; 介绍 本章主要介绍和用户点击关联更加密切的菜单控制&#xff08;Menu&#xff09; 和 气泡提示&#xff08;Popup&#xff09; 它们出现显示弹窗出现的位置都是在用户点击屏幕的位置相关 菜单控制&#xff08;Menu&…

【C】-递归

1、递归概念 递归&#xff08;Recursion&#xff09;是编程中一种重要的解决问题的方法&#xff0c;其核心思想是函数通过调用自身来解决规模更小的子问题&#xff0c;直到达到最小的、可以直接解决的基准情形&#xff08;Base Case&#xff09;。 核心&#xff1a;自己调用…

飞马LiDAR500雷达数据预处理

0 引言 在使用飞马D2000无人机搭载LiDAR500进行作业完成后&#xff0c;需要对数据进行预处理&#xff0c;方便给内业人员开展点云分类等工作。在开始操作前&#xff0c;先了解一下使用的软硬件及整体流程。 0.1 外业测量设备 无人机&#xff1a;飞马D2000S激光模块&#xff…

嵌入式鸿蒙开发环境搭建操作方法与实现

Linux环境搭建镜像下载链接: 链接:https://pan.baidu.com/s/1F2f8ED5V1KwLjyYzKVx2yQ 提取码:Leun vscode和Linux系统连接的详细过程1.下载Visual Studio Code

QT常用控件(1)

控件是构成QT的基础元素&#xff0c;例如Qwidget也是一个控件&#xff0c;提供了一个‘空’的矩形&#xff0c;我们可以往里面添加内容和处理用户输入&#xff0c;例如&#xff1a;按钮&#xff08;QpushButton&#xff09;&#xff0c;基础显示控件&#xff08;Lable&#xff…

明基编程显示器终于有优惠了,程序员快来,错过等一年!

最近618的活动已经陆续开始了&#xff0c;好多人说这是买数码产品的好时候&#xff0c;作为一名资深程序员&#xff0c;我做了不少功课&#xff0c;决定给自己升级办公设备&#xff0c;入手明基 RD 系列的显示器&#xff0c;这是市面上首家专注于我们程序员痛点和需求的产品&am…

【计算机网络】非阻塞IO——select实现多路转接

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;计算机网络 &#x1f339;往期回顾&#x1f339;&#xff1a;【计算机网络】NAT、代理服务器、内网穿透、内网打洞、局域网中交换机 &#x1f516;流水不争&#xff0…

LeetCode--23.合并k个升序链表

解题思路&#xff1a; 1.获取信息&#xff1a; 给出了多个升序链表&#xff0c;要求合并成一个升序链表&#xff0c;返回首元结点 2.分析题目&#xff1a; 外面在21题的时候&#xff0c;讲了怎样合并两个升序链表为一个升序链表&#xff0c;不了解的&#xff0c;建议去看一下21…

【推荐算法】NeuralCF:深度学习重构协同过滤的革命性突破

NeuralCF&#xff1a;深度学习重构协同过滤的革命性突破 一、算法背景知识&#xff1a;协同过滤的演进与局限1.1 协同过滤的发展历程1.2 传统矩阵分解的缺陷 二、算法理论/结构&#xff1a;NeuralCF架构设计2.1 基础NeuralCF结构2.2 双塔模型进阶结构2.3 模型实现流程对比 三、…

负载均衡相关基本概念

负载均衡在系统架构设计中至关重要&#xff0c;其核心目标是合理分配负载&#xff0c;提升系统整体性能和可靠性。本文简要介绍了负载均衡的基本概念&#xff0c;包括四层和七层负载均衡、负载均衡的使用场景和实现方式、负载均衡的常用算法以及一些配置相关知识。 1、负载均衡…

集成电路设计:从概念到实现的完整解析优雅草卓伊凡

集成电路设计&#xff1a;从概念到实现的完整解析优雅草卓伊凡 一、集成电路设计&#xff1a;芯片制造的”灵魂蓝图” 1.1 什么是集成电路设计&#xff1f; 集成电路&#xff08;IC&#xff09;设计是指通过电子设计自动化&#xff08;EDA&#xff09;工具&#xff0c;将数百…

动态规划之网格图模型(二)

文章目录 动态规划之网格图模型&#xff08;二&#xff09;LeetCode 931. 下降路径最小和思路Golang 代码 LeetCode 2684. 矩阵中移动的最大次数思路Golang 代码 LeetCode 2304. 网格中的最小路径代价思路Golang 代码 LeetCode 1289. 下降路径最小和 II思路Golang 代码 LeetCod…

robot_lab——rsl_rl的train.py整体逻辑

文章目录 Go2机器人训练流程详细分析概述1. 训练启动流程1.1 命令行参数解析RSL-RL相关参数组Isaac Sim应用启动参数组 1.2 RL配置1.3 Isaac Sim启动 2. 环境配置加载2.1 Hydra配置系统 3. 环境创建与初始化3.1 Gym环境创建3.2 Manager系统初始化3.2.1 ObservationManager3.2.2…

.NET 原生驾驭 AI 新基建实战系列(三):Chroma ── 轻松构建智能应用的向量数据库

在人工智能AI和机器学习ML迅猛发展的今天&#xff0c;数据的存储和检索需求发生了巨大变化。传统的数据库擅长处理结构化数据&#xff0c;但在面对高维向量数据时往往力不从心。向量数据库作为一种新兴技术&#xff0c;专为AI应用设计&#xff0c;能够高效地存储和查询高维向量…

8.RV1126-OPENCV 视频中添加LOGO

一.视频中添加 LOGO 图像大体流程 首先初始化VI,VENC模块并使能&#xff0c;然后创建两个线程&#xff1a;1.把LOGO灰度化&#xff0c;然后获取VI原始数据&#xff0c;其次把VI数据Mat化并创建一个感兴趣区域&#xff0c;最后把LOGO放感兴趣区域里并把数据发送给VENC。2.专门获…

API管理是什么?API自动化测试怎么搭建?

目录 一、API管理是什么 &#xff08;一&#xff09;API管理的定义 &#xff08;二&#xff09;API管理的重要性 二、API管理的主要内容 &#xff08;一&#xff09;API设计 1. 遵循标准规范 2. 考虑可扩展性 3. 保证接口的易用性 &#xff08;二&#xff09;API开发 …

GIC v3 v4 虚拟化架构

ARMV8-A架构中包含了对虚拟化的支持。为了与架构保持匹配&#xff0c;GICV3也对虚拟化做了支持。新增了以下特性&#xff1a; 对CPU interface的硬件虚拟化虚拟中断maintenance 中断&#xff1a;用于通知监管程序&#xff08;例如hypervisor&#xff09;一些特定的虚拟机事件 …