| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- import { Row, showToast } from "vant";
- import { defineComponent, onMounted, reactive } from "vue";
- import state from "/src/state";
- import request from "/src/utils/request";
- import { getQuery } from "/src/utils/queryString";
- import styles from "./index.module.less";
- import { Button, ButtonGroup, Icon, Switch, Tooltip } from "@varlet/ui";
- import "@varlet/ui/es/tooltip/style";
- import "@varlet/ui/es/button-group/style";
- import "@varlet/ui/es/switch/style";
- let extStyleConfigJson: any = {};
- export const moveData = reactive({
- /** 开启移动 */
- open: false,
- zoom: state.zoom,
- partIndex: "0",
- hasExtJson: false,
- isWeb: false,
- modelList: [] as any[],
- activeIndex: -1,
- sw: 0,
- tool: {
- isAddAndSub: false,
- },
- });
- function initSvgId() {
- const svg = document.querySelector("#osmdSvgPage1");
- if (!svg) return;
- const vfstavetempo: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-stavetempo"));
- const vftext: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-text"));
- const vfstaveSection: HTMLElement[] = []; //Array.from(svg.querySelectorAll(".vf-StaveSection"));
- const vfRepetition: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-Repetition"));
- const vflineGroup: HTMLElement[] = Array.from(svg.querySelectorAll(".vf-lineGroup"));
- let tempIndex = 1;
- [...vfstavetempo].forEach((ele) => {
- setEleId(ele, "temp" + tempIndex);
- tempIndex++;
- });
- let textIndex = 1;
- [...vftext].forEach((ele) => {
- setEleId(ele, "text" + textIndex);
- textIndex++;
- });
- let sectionIndex = 1;
- [...vfstaveSection].forEach((ele) => {
- setEleId(ele, "section" + sectionIndex);
- sectionIndex++;
- });
- let repIndex = 1;
- [...vfRepetition].forEach((ele) => {
- setEleId(ele, "repet" + repIndex);
- repIndex++;
- });
- let lineIndex = 1;
- [...vflineGroup].forEach((ele) => {
- setEleId(ele, "line" + lineIndex);
- lineIndex++;
- });
- // if (moveData.isWeb) {
- // readerModelBox();
- // }
- // if (moveData.hasExtJson) {
- // setTimeout(reloadReader, 2);
- // }
- }
- /**赋值id */
- function setEleId(ele: HTMLElement, eleId: string) {
- if (!ele || !eleId) return;
- const id = ele.getAttribute("id");
- if (!id) {
- ele.setAttribute("id", eleId);
- }
- createModelBox(ele as any);
- }
- function createModelBox(ele: SVGAElement) {
- const musicContainer = document.getElementById("musicAndSelection")?.getBoundingClientRect() || { x: 0, y: 0 };
- const parentLeft = musicContainer.x || 0;
- const parentTop = musicContainer.y || 0;
- const noteBbox = ele.getBoundingClientRect();
- const bbox = {
- left: noteBbox.x - parentLeft + "px",
- top: noteBbox.y - parentTop + "px",
- width: noteBbox.width + "px",
- height: noteBbox.height + "px",
- };
- const type = ele.getAttribute("class");
- moveData.modelList.push({
- id: ele.getAttribute("id"),
- bbox,
- type,
- isMove: false,
- left: noteBbox.left,
- top: noteBbox.top,
- width: noteBbox.width,
- height: noteBbox.height,
- x: 0,
- y: 0,
- zoom: state.zoom,
- isDelete: false,
- d2: getLineGroupPathDx(ele as any),
- dx: 0,
- });
- }
- function getBox(ele: SVGAElement) {
- if (!ele) return {};
- const musicContainer = document.getElementById("musicAndSelection")?.getBoundingClientRect() || { x: 0, y: 0 };
- const parentLeft = musicContainer.x || 0;
- const parentTop = musicContainer.y || 0;
- const box = ele.getBoundingClientRect();
- return {
- left: box.x - parentLeft,
- top: box.y - parentTop,
- width: box.width,
- height: box.height,
- };
- }
- // 过滤数据
- export const filterMoveData = async () => {
- const examSongId = state.examSongId;
- if (examSongId) {
- const list = moveData.modelList
- .filter((n) => n.isMove)
- .map((n) => {
- const item: any = {
- id: n.id,
- isMove: n.isMove,
- isDelete: n.isDelete,
- x: n.x,
- y: n.y,
- zoom: n.zoom,
- w: moveData.sw,
- type: n.type,
- };
- if (n.type === "vf-lineGroup") {
- item.dx = n.dx;
- }
- return item;
- });
- if (!list.length) {
- showToast("请移动元素后再保存");
- return
- }
- extStyleConfigJson[moveData.partIndex] = list;
- console.log("🚀 ~ extStyleConfigJson", extStyleConfigJson)
- const res = await request.post("/musicSheet/img", {
- requestType: "json",
- data: {
- id: examSongId,
- extStyleConfigJson: JSON.stringify(extStyleConfigJson),
- }
- });
- if (res && res.code == 200) {
- showToast("保存成功");
- }
- clearActiveModel();
- }
- };
- // 移动
- const dragData = {
- open: false,
- startX: 0,
- startY: 0,
- x: 0,
- y: 0,
- };
- // 记录
- export const undoData = reactive({
- undoList: [] as Array<any>, // 撤销列表
- redoList: [] as Array<any>, // 回退列表
- activeItem: null,
- });
- function onDown(e: MouseEvent) {
- const el: any = e.target;
- const index = moveData.modelList.findIndex((n) => n.id === el.dataset.id);
- if (index > -1) {
- const item = moveData.modelList[index];
- moveData.activeIndex = index;
- dragData.startX = e.clientX;
- dragData.startY = e.clientY;
- dragData.x = item.x;
- dragData.y = item.y;
- // console.log("🚀 ~ 按下", index, el, item.x, item.y);
- document.onmousemove = onMove;
- document.onmouseup = onUp;
- dragData.open = true;
- if (item.type === "vf-lineGroup") {
- moveData.tool.isAddAndSub = true;
- } else {
- moveData.tool.isAddAndSub = false;
- }
- undoData.activeItem = { ...item };
- return;
- }
- moveData.activeIndex = -1;
- }
- function onMove(e: MouseEvent) {
- if (dragData.open) {
- const _x = e.clientX - dragData.startX + dragData.x;
- const _y = e.clientY - dragData.startY + dragData.y;
- setModelPostion(moveData.modelList[moveData.activeIndex], _x, _y);
- }
- }
- function onUp(e: MouseEvent) {
- // console.log("🚀 ~ 抬起");
- document.onmousemove = null;
- document.onmouseup = null;
- dragData.open = false;
- const _x = e.clientX - dragData.startX + dragData.x;
- const _y = e.clientY - dragData.startY + dragData.y;
- if (_x || _y) {
- moveData.modelList[moveData.activeIndex].isMove = true;
- moveData.modelList[moveData.activeIndex].x = _x;
- moveData.modelList[moveData.activeIndex].y = _y;
- if (undoData.activeItem) {
- undoData.undoList.push({ ...(undoData.activeItem as any) });
- }
- }
- undoData.activeItem = null;
- }
- /** 渲染svg元素的属性 */
- const renderSvgItem = (item: any) => {
- setModelPostion(item, item.x, item.y);
- if (item.isDelete) {
- const g = document.querySelector("#" + item.id)!;
- g && ((g as any).style.display = "none");
- } else {
- const g = document.querySelector("#" + item.id)!;
- g && ((g as any).style.display = "");
- }
- };
- /** 设置元素位置 */
- function setModelPostion(item: any, x: number, y: number) {
- if (item) {
- const g = document.querySelector("#" + item.id)!;
- const el: HTMLElement = document.querySelector(`[data-id=${item.id}]`)!;
- if (x === 0 && y === 0) {
- g && g.removeAttribute("transform");
- el && (el.style.transform = "");
- } else {
- g && g.setAttribute("transform", `translate(${x / moveData.zoom}, ${y / moveData.zoom})`);
- el && (el.style.transform = `translate(${x}px, ${y}px)`);
- }
- }
- }
- /** 删除元素 */
- const handleDeleteMoveNote = () => {
- const item = moveData.modelList[moveData.activeIndex];
- if (item) {
- moveData.modelList[moveData.activeIndex].isMove = true;
- undoData.undoList.push({ ...moveData.modelList[moveData.activeIndex] });
- moveData.modelList[moveData.activeIndex].isDelete = !item.isDelete;
- const g = document.querySelector("#" + item.id)!;
- g && ((g as any).style.display = moveData.modelList[moveData.activeIndex].isDelete ? "none" : '');
- } else {
- showToast("选中需要删除的元素");
- }
- };
- /** 重置数据 */
- const resetMoveNote = () => {
- for (let i = 0; i < moveData.modelList.length; i++) {
- moveData.modelList[i].x = 0;
- moveData.modelList[i].y = 0;
- moveData.modelList[i].isMove = false;
- moveData.modelList[i].isDelete = false;
- moveData.modelList[i].dx = 0;
- renderSvgItem(moveData.modelList[i]);
- if (moveData.modelList[i].type === "vf-lineGroup") {
- renderLineGroup(moveData.modelList[i]);
- }
- }
- clearActiveModel();
- };
- function clearActiveModel() {
- for (let i = 0; i < moveData.modelList.length; i++) {
- const item: HTMLElement = document.querySelector(`[data-id=${moveData.modelList[i].id}]`)!;
- if (item?.classList?.contains("activeModel")) {
- item.classList.remove("activeModel");
- }
- }
- moveData.activeIndex = -1;
- moveData.tool.isAddAndSub = false;
- }
- // 增加或减少, 渐强和渐弱的线长
- const handleAddAndSub = (type: 'add' | 'sub') => {
- if (!["add", "sub"].includes(type)) return;
- const lineGroup = moveData.modelList[moveData.activeIndex];
- if (!lineGroup || lineGroup.type !== "vf-lineGroup") return;
- lineGroup.isMove = true;
- const step = type === "add" ? 10 : -10;
- undoData.undoList.push({ ...moveData.modelList[moveData.activeIndex] });
- moveData.modelList[moveData.activeIndex].dx = lineGroup.dx + step;
- renderLineGroup(moveData.modelList[moveData.activeIndex]);
- };
- // 获取line的dx
- function getLineGroupPathDx(lineGroup: HTMLElement) {
- if (!lineGroup) return 0;
- const lines = lineGroup.querySelectorAll("path");
- if (lines?.length) {
- for (let i = 0; i < lines.length; i++) {
- const path = lines[i];
- let d = path.getAttribute("d");
- if (d) {
- let dx1: any = d.split("M")?.[1]?.split(" ") || [];
- let dx2: any = d.split("L")?.[1]?.split(" ") || [];
- dx1 = dx1[0] && !isNaN(Number(dx1[0])) ? Number(dx1[0]) : 0;
- dx2 = dx2[0] && !isNaN(Number(dx2[0])) ? Number(dx2[0]) : 0;
- if (dx1 && dx2) {
- if (dx1 < dx2) {
- return dx2;
- } else {
- return dx1;
- }
- }
- }
- }
- }
- return 0;
- }
- function renderLineGroup(lineGroup: any) {
- const group = document.querySelector("#" + lineGroup.id);
- if (!group) return;
- const lines = group.querySelectorAll("path");
- if (lines?.length) {
- for (let i = 0; i < lines.length; i++) {
- const path = lines[i];
- let d = path.getAttribute("d");
- if (d) {
- let dx1: any = d.split("M")?.[1]?.split(" ") || [];
- let dx2: any = d.split("L")?.[1]?.split(" ") || [];
- dx1 = dx1[0] && !isNaN(Number(dx1[0])) ? Number(dx1[0]) : 0;
- dx2 = dx2[0] && !isNaN(Number(dx2[0])) ? Number(dx2[0]) : 0;
- if (dx1 && dx2) {
- if (dx1 < dx2) {
- d = d.replace(dx2, lineGroup.d2 + lineGroup.dx + "");
- } else {
- d = d.replace(dx1, lineGroup.d2 + lineGroup.dx + "");
- }
- path.setAttribute("d", d);
- }
- }
- }
- const { width } = getBox(group as any);
- const div: HTMLElement = document.querySelector(`[data-id=${lineGroup.id}]`)!;
- div && (div.style.width = width + "px");
- }
- }
- /** 撤销 */
- const handleUndo = () => {
- const preItem = undoData.undoList.pop();
- // console.log("🚀 ~ preItem", preItem)
- if (preItem) {
- const itemIndex = moveData.modelList.findIndex((n: any) => n.id === preItem.id);
- if (itemIndex > -1) {
- moveData.modelList[itemIndex] = preItem;
- renderSvgItem(moveData.modelList[itemIndex])
- if (preItem.type === "vf-lineGroup") {
- renderLineGroup(preItem);
- }
- }
- }
- };
- /** 根据移动数据渲染 */
- export const renderForMoveData = () => {
- if (state.extStyleConfigJson) {
- try {
- extStyleConfigJson = JSON.parse(state.extStyleConfigJson);
- } catch (error) {
- extStyleConfigJson = {};
- }
- }
- if (!extStyleConfigJson || !extStyleConfigJson?.[moveData.partIndex]) return;
- initSvgId();
- const list = extStyleConfigJson?.[moveData.partIndex];
- if (list && Array.isArray(list)) {
- console.log("🚀 ~ list", list);
- list.forEach((item: any) => {
- const index = moveData.modelList.findIndex((n: any) => n.id === item.id);
- if (index > -1) {
- moveData.modelList[index] = {
- ...moveData.modelList[index],
- ...item
- };
- renderSvgItem(moveData.modelList[index]);
- if (item.type === "vf-lineGroup") {
- renderLineGroup(moveData.modelList[index]);
- }
- }
- });
- }
- };
- export default defineComponent({
- name: "move-music-score",
- setup() {
- const query = getQuery();
- const isOpen = query.isMove === "1" ? true : false;
- console.log("🚀 ~ isOpen:", isOpen);
- onMounted(() => {
- // if (isOpen) {
- // initSvgId();
- // }
- // renderForMoveData();
- const toolBox = document.getElementById("toolBox");
- toolBox && document.body.appendChild(toolBox);
- });
- return () => (
- <div class={[moveData.open ? "" : styles.moveDisabled]}>
- <div class={styles.toolBox} id="toolBox">
- <Switch v-model={moveData.open} />
- {moveData.open && (
- <>
- {moveData.tool.isAddAndSub && (
- <ButtonGroup size="small" elevation={false}>
- <Button onClick={() => handleAddAndSub('add')}>加</Button>
- <Button onClick={() => handleAddAndSub('sub')}>减</Button>
- </ButtonGroup>
- )}
- {/* <ButtonGroup size="small">
-
- <Button>
- <Icon name="arrow-down" style={{ transform: "rotate(-90deg)" }} />
- </Button>
- </ButtonGroup> */}
- <Button size="small" onClick={handleUndo} disabled={undoData.undoList.length ? false : true}>
- <Icon name="arrow-down" style={{ transform: "rotate(90deg)" }} />
- </Button>
- <Button size="small" onClick={handleDeleteMoveNote} disabled={moveData.activeIndex > -1 ? false : true}>
- {moveData.modelList[moveData.activeIndex]?.isDelete ? '显示元素' : '删除元素'}
- </Button>
- <Button size="small" onClick={resetMoveNote}>
- 重置数据
- </Button>
- <Button size="small" type="primary" onClick={filterMoveData}>
- 保存数据
- </Button>
- </>
- )}
- </div>
- {moveData.modelList.map((item: any, index: number) => {
- return (
- <div class={[styles.noteMove, moveData.activeIndex === index && styles.activeModel]} style={item.bbox} data-id={item.id} onMousedown={onDown}></div>
- );
- })}
- </div>
- );
- },
- });
|