recogito-js:用于文本注释/图像注释的前端插件

创建批注:

 

继续批注:

右侧批注列表:

1、功能与应用

  • 文本注释:recogito-js可以将注释功能添加到网页上,或者作为构建完全自定义注释应用程序的工具箱。
  • 图像注释:除了文本注释外,它还支持为网页中的图像添加绘图、注释和标签功能。
  • PDF注释:通过@recogito/recogito-react-pdf插件,它还能够支持在React中注释PDF文档。

2、官网及示例

官网:https://github.com/recogito/recogito-js/wiki/API-Reference

示例:https://recogito.github.io/recogito-js/

3、需求:

前面的文章提到过很多的tinyMCE、Vditor、cherryMarkdown、wangEditor等等markdown和富文本编辑器,在这些编辑器生成的文本内容的预览基础上要加上批注功能,用户选中文本后就要弹出批注弹窗,确认批注后右侧会相应展示出批注内容,同时在右侧进行批注的编辑、删除

4、安装与使用:

npm i @recogito/recogito-js@1.8.2

以下示例为文本注释功能:

import { Recogito } from "@recogito/recogito-js";
import "@recogito/recogito-js/dist/recogito.min.css";

// 初始化批注
const initRecogito = () => {
  getAnnoList();
  r = new Recogito({
    content: document.querySelector(".artDetail"), // 批注区域
    readOnly: false,  // 是否只读
    locale: "auto", // 可选择语言 auto会根据浏览器设置选择语言
  });
  r.setServerTime(Date.now()); // 设置批注日期
  r.setAuthInfo({   // 这里设置每个批注携带的默认信息
    id: useUserStore().userId,
    displayName: useUserStore().nickName,
  });
  // 创建批注事件
  r.on("createAnnotation", async function (annotation, overrideId) {
    // 定义一个getInitAnnotate方法拿到创建的这个批注信息
    let newAnno = getInitAnnotate("create", annotation);
    // 因为批注插件不管有没有输入内容都会创建,这里要求了没有批注内容时不允许新建批注
    if (!newAnno.annotationContent?.trim()?.length) {
      getAnnoList(); // 刷新批注列表避免页面出现空批注内容
      return proxy.$modal.msgWarning("请先输入批注内容");
    }
    // 将批注信息存入后端
    submitAnnotation(newAnno)
      .then(({ data }) => {
        recogitoList.value.push(data);  // 在页面右侧回展示批注信息
        proxy.$modal.msgSuccess("新增成功!");
      })
      .catch((err) => {
        getAnnoList();// 刷新批注列表避免页面出现空批注内容
      });
  });

 

  // 在已有批注基础上补充批注
  r.on("updateAnnotation", function (annotation, previous) {
    let newAnno = getInitAnnotate("update", annotation);
    if (!newAnno.annotationContent?.trim()?.length) {
      getAnnoList();
      return proxy.$modal.msgWarning("请先输入批注内容");
    }
    submitAnnotation(newAnno)
      .then(({ data }) => {
        // 补充批注时
        let index = recogitoList.value.findIndex((item) => item.id === data.id);
        recogitoList.value[index] = data;
        proxy.$modal.msgSuccess("新增成功!");
      })
      .catch((err) => {
        getAnnoList();
      });
  });
};

// 更改批注参数
const getInitAnnotate = (title, newAnno, pkId) => {
  let data = {};
  // 创建批注时
  if (title === "create") {
    data.annotationContent = newAnno.body[0]?.value;
    data.textContent = newAnno.target.selector.find(
      (item) => item.type === "TextQuoteSelector"
    )?.exact;
  // 修改批注时
  } else if (title === "update") {
    data.annotationContent = newAnno.body[newAnno.body?.length - 1]?.value;
  } else {
    // 通过外部input框编辑批注
    let annoBody = newAnno.body.find((item) => item.pkId === pkId);
    data.annotationContent = annoBody?.iptValue;
    data.pkId = pkId;
  }
  let annoPosition = newAnno.target.selector.find(
    (item) => item.type === "TextPositionSelector"
  );
  // 按照后端入参要求组装批注内容的结构
  data.annotationId = newAnno.id;
  data.createdBy = useUserStore().name;
  data.endCoordinate = annoPosition.end;
  data.startCoordinate = annoPosition.start;
  data.knwlgId = artDetails.value.pkId;
  data.knwlgNo = artDetails.value.knwlgNo;
  return data;
};

// 获取批注列表并回显
const getAnnoList = () => {
  getAnnotationList({ knwlgId: artDetails.value.pkId })
    .then((res) => {
      recogitoList.value = res.data;  // 批注列表
      setTimeout(() => {
        r.clearAnnotations(); //清除所有批注
        r.setAnnotations(recogitoList.value); // 设置已有批注内容
      }, 500);
    })
    .catch(() => {});
};

// 根据批注id在点击右侧批注列表激活文本域内批注弹窗
const selectAnnotation = (id) => {
  let domList = document.querySelectorAll(".r6o-annotation");
  let activeTop =
    Array.from(domList).find(
      (item) => item.dataset.id === id && item.innerText?.length
    )?.offsetTop - 5;
  document.querySelector(".article-container").scrollTop = activeTop;
  r.selectAnnotation(id);
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

测试用例设计方法-因果图法

大家好,在软件开发过程中,测试是确保产品质量和稳定性的关键步骤。而设计有效的测试用例则是保证测试过程高效和全面的重要因素之一。在各种测试用例设计方法中,因果图法作为一种结构化和系统化的方法,日益受到测试人员的青睐。 因…

python练习题2

python期考复习题 目录 1. 判断n**2的值每一位互不相同​编辑 2. 密码 3. 图书版号 4. 情感分类矩阵 5. 计算数对个数 1. 判断n**2的值每一位互不相同 def isdiff(n):sstr(n)for i in range(len(s)):for j in range(len(s)):if i!j:if s[i]s[j]:return Falsereturn Truel…

ET9中ETTask传递新的Context原理

ET9中ETTask传递新的Context原理 前言 每一个异步函数都会创建两个对象, 第1个是当前异步函数返回值(ETTASK)对应的ETAsyncTaskMethodBuilder,通过这个类的静态方法Create创建返回,这个builder类中会有一个Task对象&…

FME实现批量合并shapefile文件数据,并提取原文件名,输出到属性表字段中的解决方法

目录 一、实现效果 二、实现过程 1.读取数据 2.暴露文件名属性 3.设置文件名字段 4.输出成果 5.模板的使用 三、总结 今天来介绍如何使用FME软件来实现对多个shapefile数据进行批量合并,同时提取原文件名并存储到合并后shapefile数据属性表字段中的方法&…

中小企业的数字化转型业务场景落地案例

引言:随着商业活动的复杂化和全球化程度的提高,合同作为商业交易的重要组成部分,其数量、条款和复杂性都在不断增加。企业面临着越来越多的合同管理挑战,包括合同数量增多、条款繁琐、文件分散存储等问题。而中小企业由于管理不到…

HMI 的 UI 风格,精妙无比

HMI 的 UI 风格,精妙无比

Shopee本土店选品有什么技巧?EasyBoss ERP为你整理了6个高效选品的方法!

电商圈有句话叫:七分靠选品,三分靠运营,选品对了,事半功倍,选品错了,功亏一篑! 很多卖家都会为选品发愁,特别对于Shopee本土店卖家来说,要囤货到海外仓,如果…

前端 Array.sort() 源码学习

源码地址 V8源码Array 710行开始为sort()相关 Array.sort()方法是那种排序呢&#xff1f; 去看源码主要是源于这个问题 // In-place QuickSort algorithm. // For short (length < 22) arrays, insertion sort is used for efficiency.源码中的第一句话就回答了我的问题…

QT的keypressevent只响应功能键不响应字母键或者组合键

参考https://bbs.csdn.net/topics/392378467 这位兄弟准确说明了解决方案。 在pyqt中&#xff0c;则在__init__中添加 self.grabKeyboard()

专题页面设计指南:从构思到实现

如何设计专题页&#xff1f;你有什么想法&#xff1f;专题页的设计主要以发扬产品优势为核心。一个好的专题页可以从不同的角度向用户介绍产品&#xff0c;扩大产品的相关优势&#xff0c;表达产品的优势&#xff0c;让用户在短时间内了解产品。因此&#xff0c;在设计详细信息…

数据采集Selenium中的弹窗处理

在爬虫技术中&#xff0c;弹窗处理是一个常见但具有挑战性的问题。Selenium作为一个强大的网页自动化工具&#xff0c;可以帮助我们有效地处理网页中的各种弹窗。本文将概述如何使用Selenium处理弹窗&#xff0c;并提供实现代码&#xff0c;代码中将使用代理IP技术。 概述 弹…

基于Java微信小程序火锅店点餐系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

突然!某大客户核心凌晨突然崩溃....

这几天实在太忙&#xff0c;刚弄完文档。业务线的同事就找到我&#xff0c;说一个银行客户的核心系统昨晚出了故障&#xff0c;还没找到原因&#xff0c;希望能帮忙分析下。 从提供的信息来看是业务跑任务报错&#xff0c;遇到了Oracle-00600和ora-07445 错误。 Doing block re…

Zynq7000系列FPGA中的DMA控制器——PL外设请求接口

图9-4中展示了PL外设请求接口主要由两部分组成&#xff1a;PL外设请求总线和DMAC确认总线。这两部分分别使用特定的前缀进行标识&#xff0c;具体如下&#xff1a; PL外设请求总线&#xff08;PL Peripheral Request Bus&#xff09;&#xff1a; 前缀&#xff1a;DR功能&…

YOLO模型评价指标

在模型训练完成之后&#xff0c;需要对模型的优劣作出评估&#xff0c;YOLO系列算法的评价指标包括&#xff1a; 1. 准确率&#xff08;Precision&#xff09;&#xff1a;指模型预测为正样本中实际为正样本的比例。 &#x1d447;&#x1d443;、&#x1d439;&#x1d443;、…

uniapp字体ttf在小程序报错,解决方法

文章目录 导文解决方法1&#xff1a;把字体改成base64格式解决方法2&#xff1a;改成线上模式 导文 报错1&#xff1a; uniapp 小程序报错&#xff1a;app.js错误: Error: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ModuleBuildErro…

【Java Web】Pinia实现组件间数据共享

目录 一、Pinia概述 二、Pinia基本用法 一、Pinia概述 在前端工程化的开发环境中&#xff0c;当多个组件(.vue)文件需要使用同一个数据对象时&#xff0c;传统的方法可以使用组件传参或者路由传参来解决但此两种方式都有自己的缺点。pinia可以将多个组件需要共享使用的数据单独…

2024热门骨传导蓝牙耳机怎么选?超全的选购攻略附带好物推荐!

对于很多喜欢运动健身的小伙伴&#xff0c;在现在市面上这么多种类耳机的选择上&#xff0c;对于我来说的话还是很推荐大家去选择骨传导运动耳机的&#xff0c;相较于普通的入耳式蓝牙耳机&#xff0c;骨传导耳机是通过振动来传输声音的&#xff0c;而入耳式耳机则是通过空气传…

餐饮冷库安全守护神:可燃气体报警器检定的科学性与有效性

随着餐饮业的快速发展&#xff0c;冷库成为储存食材、保证食品质量的重要场所。 然而&#xff0c;由于冷库环境的特殊性&#xff0c;如密封性强、温度低、湿度大等&#xff0c;一旦冷库内发生可燃气体泄露&#xff0c;后果将不堪设想。因此&#xff0c;在餐饮冷库中安装并合理…

武汉星起航:自运营团队深耕亚马逊,智慧运营打造跨境电商新标杆

在全球化的浪潮下&#xff0c;跨境电商已成为企业拓展海外市场的重要渠道。而亚马逊作为全球领先的电商平台&#xff0c;其巨大的市场潜力和成熟的运营体系吸引了无数卖家竞相入驻。武汉星起航电子商务有限公司正是众多成功入驻亚马逊的卖家之一&#xff0c;其自运营团队凭借多…