feat: areas of documents
This commit is contained in:
parent
9ced4f6f29
commit
09f3466073
Binary file not shown.
@ -6,4 +6,18 @@ type Entity struct {
|
|||||||
Name string
|
Name string
|
||||||
Path string
|
Path string
|
||||||
ProjectId string
|
ProjectId string
|
||||||
|
Areas []Area
|
||||||
|
}
|
||||||
|
|
||||||
|
type Area struct {
|
||||||
|
Id string
|
||||||
|
Name string
|
||||||
|
StartX int
|
||||||
|
StartY int
|
||||||
|
EndX int
|
||||||
|
EndY int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entity) AddArea(a Area) {
|
||||||
|
e.Areas = append(e.Areas, a)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,12 +19,12 @@ func (collection *DocumentCollection) AddDocument(document Entity) {
|
|||||||
collection.Documents = append(collection.Documents, document)
|
collection.Documents = append(collection.Documents, document)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (collection *DocumentCollection) GetDocumentById(id string) Entity {
|
func (collection *DocumentCollection) GetDocumentById(id string) *Entity {
|
||||||
var foundDocument Entity
|
var foundDocument *Entity
|
||||||
|
|
||||||
for _, d := range collection.Documents {
|
for index, d := range collection.Documents {
|
||||||
if d.Id == id {
|
if d.Id == id {
|
||||||
foundDocument = d
|
foundDocument = &collection.Documents[index]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useRef } from "react"
|
import React, { useEffect, useRef, useState } from "react"
|
||||||
import { useProject } from "../../context/Project/provider"
|
import { useProject } from "../../context/Project/provider"
|
||||||
|
import { ipc } from "../../wailsjs/wailsjs/go/models"
|
||||||
|
|
||||||
|
|
||||||
const loadImage = (path: string): Promise<HTMLImageElement> => {
|
const loadImage = (path: string): Promise<HTMLImageElement> => {
|
||||||
@ -14,31 +15,171 @@ const loadImage = (path: string): Promise<HTMLImageElement> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DocumentRenderer = () => {
|
const DocumentRenderer = () => {
|
||||||
const { getSelectedDocument } = useProject()
|
const { getSelectedDocument, requestAddArea } = useProject()
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 })
|
||||||
|
const selectedDocument = getSelectedDocument()
|
||||||
|
const areas = selectedDocument?.areas
|
||||||
|
const documentCanvas = useRef<HTMLCanvasElement>(null)
|
||||||
|
const areaCanvas = useRef<HTMLCanvasElement>(null)
|
||||||
|
const drawingCanvas = useRef<HTMLCanvasElement>(null)
|
||||||
|
|
||||||
|
// console.log('selectedDocument: ', selectedDocument)
|
||||||
|
|
||||||
|
let downClickX = 0
|
||||||
|
let downClickY = 0
|
||||||
|
let isMouseDown = false
|
||||||
|
|
||||||
|
const applyCanvasSizes = (size: { width: number, height: number }) => {
|
||||||
|
const documentCanvasInstance = documentCanvas.current
|
||||||
|
if (!documentCanvasInstance) return
|
||||||
|
documentCanvasInstance.width = size.width
|
||||||
|
documentCanvasInstance.height = size.height
|
||||||
|
|
||||||
|
const areaCanvasInstance = areaCanvas.current
|
||||||
|
if (!areaCanvasInstance) return
|
||||||
|
areaCanvasInstance.width = size.width
|
||||||
|
areaCanvasInstance.height = size.height
|
||||||
|
|
||||||
|
const drawingCanvasInstance = drawingCanvas.current
|
||||||
|
if (!drawingCanvasInstance) return
|
||||||
|
drawingCanvasInstance.width = size.width
|
||||||
|
drawingCanvasInstance.height = size.height
|
||||||
|
}
|
||||||
|
|
||||||
const applyDocumentToCanvas = async (path: string) => {
|
const applyDocumentToCanvas = async (path: string) => {
|
||||||
const image = await loadImage(path)
|
const image = await loadImage(path)
|
||||||
|
applyCanvasSizes({ width: image.naturalWidth, height: image.naturalHeight })
|
||||||
|
|
||||||
const canvas = canvasRef.current
|
const documentCanvasInstance = documentCanvas.current
|
||||||
if (!canvas) return
|
if (!documentCanvasInstance) return
|
||||||
canvas.width = image.naturalWidth
|
|
||||||
canvas.height = image.naturalHeight
|
|
||||||
|
|
||||||
const context = canvas.getContext('2d')
|
const context = documentCanvasInstance.getContext('2d')
|
||||||
if (!context) return
|
if (!context) return
|
||||||
context.drawImage(image, 0, 0, image.width, image.height)
|
context.drawImage(image, 0, 0, image.width, image.height)
|
||||||
|
|
||||||
|
if (areas) applyAreasToCanvas()
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyAreasToCanvas = () => {
|
||||||
|
if (!areas || !areas.length) return
|
||||||
|
const areaCanvasInstance = areaCanvas.current
|
||||||
|
if (!areaCanvasInstance) return
|
||||||
|
const context = areaCanvasInstance.getContext("2d")
|
||||||
|
if (!context) return
|
||||||
|
|
||||||
|
context.clearRect(0, 0, areaCanvasInstance.width, areaCanvasInstance.height)
|
||||||
|
|
||||||
|
areas.forEach(a => {
|
||||||
|
console.log('area: ', a)
|
||||||
|
const width = a.endX - a.startX
|
||||||
|
const height = a.endY - a.startY
|
||||||
|
const x = a.startX
|
||||||
|
const y = a.startY
|
||||||
|
console.log(`context.rect: `, x, y, width, height)
|
||||||
|
context.rect(x, y, width, height)
|
||||||
|
context.lineWidth = 2
|
||||||
|
context.strokeStyle = '#dc8dec'
|
||||||
|
context.stroke()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseDown = (e: React.MouseEvent) => {
|
||||||
|
const drawingCanvasInstance = drawingCanvas.current
|
||||||
|
if (!drawingCanvasInstance) return
|
||||||
|
|
||||||
|
downClickX = e.nativeEvent.offsetX
|
||||||
|
downClickY = e.nativeEvent.offsetY
|
||||||
|
isMouseDown = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseUp = async (e: React.MouseEvent) => {
|
||||||
|
const drawingCanvasInstance = drawingCanvas.current
|
||||||
|
if (!drawingCanvasInstance) return
|
||||||
|
|
||||||
|
const mouseX = e.nativeEvent.offsetX
|
||||||
|
const mouseY = e.nativeEvent.offsetY
|
||||||
|
|
||||||
|
let startX: number, endX: number
|
||||||
|
if (downClickX < mouseX) {
|
||||||
|
startX = downClickX
|
||||||
|
endX = mouseX
|
||||||
|
} else {
|
||||||
|
startX = mouseX
|
||||||
|
endX = downClickX
|
||||||
|
}
|
||||||
|
|
||||||
|
let startY: number, endY: number
|
||||||
|
if (downClickY < mouseY) {
|
||||||
|
startY = downClickY
|
||||||
|
endY = mouseY
|
||||||
|
} else {
|
||||||
|
startY = mouseY
|
||||||
|
endY = downClickY
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedDocument?.id)
|
||||||
|
requestAddArea(selectedDocument.id, { startX, startY, endX, endY }).then(response => {
|
||||||
|
console.log('requestAddArea: ', response)
|
||||||
|
}).catch(err => console.log('err requestAddArea :', err))
|
||||||
|
|
||||||
|
const context = drawingCanvasInstance.getContext('2d')
|
||||||
|
context?.clearRect(0, 0, drawingCanvasInstance.width, drawingCanvasInstance.height)
|
||||||
|
isMouseDown = false
|
||||||
|
downClickX = 0
|
||||||
|
downClickY = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseMove = (e: React.MouseEvent) => {
|
||||||
|
const drawingCanvasInstance = drawingCanvas.current
|
||||||
|
if (!drawingCanvasInstance) return
|
||||||
|
|
||||||
|
let mouseX = e.nativeEvent.offsetX
|
||||||
|
let mouseY = e.nativeEvent.offsetY
|
||||||
|
|
||||||
|
if (isMouseDown) {
|
||||||
|
const context = drawingCanvasInstance.getContext('2d')
|
||||||
|
if (!context) return
|
||||||
|
|
||||||
|
context.clearRect(0, 0, drawingCanvasInstance.width, drawingCanvasInstance.height)
|
||||||
|
context.beginPath()
|
||||||
|
const width = mouseX - downClickX
|
||||||
|
const height = mouseY - downClickY
|
||||||
|
context.rect(downClickX, downClickY, width, height)
|
||||||
|
context.strokeStyle = '#000'
|
||||||
|
context.lineWidth = 2
|
||||||
|
context.stroke()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const selectedDocument = getSelectedDocument()
|
if (selectedDocument?.path) applyDocumentToCanvas(selectedDocument.path)
|
||||||
const documentPath = selectedDocument?.path
|
}, [selectedDocument?.id])
|
||||||
if (documentPath) applyDocumentToCanvas(selectedDocument.path)
|
|
||||||
}, [getSelectedDocument])
|
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<canvas ref={canvasRef}></canvas>
|
applyAreasToCanvas()
|
||||||
)
|
}, [areas, areas?.length])
|
||||||
|
|
||||||
|
return <div className="relative">
|
||||||
|
<canvas
|
||||||
|
className="absolute"
|
||||||
|
ref={documentCanvas}
|
||||||
|
/>
|
||||||
|
<canvas
|
||||||
|
className="absolute"
|
||||||
|
ref={areaCanvas}
|
||||||
|
// width={canvasSize.width}
|
||||||
|
// height={canvasSize.height}
|
||||||
|
/>
|
||||||
|
<canvas
|
||||||
|
className="absolute"
|
||||||
|
ref={drawingCanvas}
|
||||||
|
onMouseDown={handleMouseDown}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
onMouseMove={handleMouseMove}
|
||||||
|
// width={canvasSize.width}
|
||||||
|
// height={canvasSize.height}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DocumentRenderer
|
export default DocumentRenderer
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { createContext, ReactNode, useContext, useState } from 'react'
|
import { createContext, ReactNode, useContext, useState } from 'react'
|
||||||
import { GetDocuments, RequestAddDocument, RequestAddDocumentGroup } from '../../wailsjs/wailsjs/go/ipc/Channel'
|
import { GetDocuments, RequestAddArea, RequestAddDocument, RequestAddDocumentGroup } from '../../wailsjs/wailsjs/go/ipc/Channel'
|
||||||
import { ipc } from '../../wailsjs/wailsjs/go/models'
|
import { ipc } from '../../wailsjs/wailsjs/go/models'
|
||||||
import { ProjectContextType, ProjectProps } from './types'
|
import { AddAreaProps, ProjectContextType, ProjectProps } from './types'
|
||||||
import makeDefaultProject from './makeDefaultProject'
|
import makeDefaultProject from './makeDefaultProject'
|
||||||
|
import { LogPrint } from '../../wailsjs/wailsjs/runtime/runtime'
|
||||||
|
|
||||||
const ProjectContext = createContext<ProjectContextType>(makeDefaultProject())
|
const ProjectContext = createContext<ProjectContextType>(makeDefaultProject())
|
||||||
|
|
||||||
@ -18,33 +19,41 @@ export function ProjectProvider({ children, projectProps }: Props) {
|
|||||||
|
|
||||||
const updateDocuments = async () => {
|
const updateDocuments = async () => {
|
||||||
GetDocuments().then(response => {
|
GetDocuments().then(response => {
|
||||||
setDocuments(response.documents)
|
if (response.documents.length) setDocuments(response.documents)
|
||||||
setGroups(response.groups)
|
if (response.groups.length) setGroups(response.groups)
|
||||||
Promise.resolve(response)
|
Promise.resolve(response)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestAddDocument = async (groupId: string, documentName: string) => {
|
const requestAddDocument = async (groupId: string, documentName: string) => {
|
||||||
const response = await RequestAddDocument(groupId, documentName)
|
const response = await RequestAddDocument(groupId, documentName)
|
||||||
if (response.id) updateDocuments()
|
if (response.id) await updateDocuments()
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestAddDocumentGroup = async (groupName: string) => {
|
const requestAddDocumentGroup = async (groupName: string) => {
|
||||||
const response = await RequestAddDocumentGroup(groupName)
|
const response = await RequestAddDocumentGroup(groupName)
|
||||||
if (response.id) updateDocuments()
|
if (response.id) await updateDocuments()
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestAddArea = async (documentId: string, area: AddAreaProps): Promise<ipc.Area> => {
|
||||||
|
const response = await RequestAddArea(documentId, new ipc.Area(area))
|
||||||
|
|
||||||
|
if (response.id) await updateDocuments()
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSelectedDocument = () => documents.find(d => d.id === selectedDocumentId)
|
const getSelectedDocument = () => documents.find(d => d.id === selectedDocumentId)
|
||||||
|
|
||||||
if (!documents.length || !groups.length) updateDocuments()
|
if (!documents.length && !groups.length) updateDocuments()
|
||||||
|
|
||||||
const value = {
|
const value = {
|
||||||
id: '',
|
id: '',
|
||||||
documents,
|
documents,
|
||||||
groups,
|
groups,
|
||||||
getSelectedDocument,
|
getSelectedDocument,
|
||||||
|
requestAddArea,
|
||||||
requestAddDocument,
|
requestAddDocument,
|
||||||
requestAddDocumentGroup,
|
requestAddDocumentGroup,
|
||||||
selectedDocumentId,
|
selectedDocumentId,
|
||||||
|
|||||||
@ -6,10 +6,19 @@ export type ProjectProps = {
|
|||||||
groups: ipc.Group[],
|
groups: ipc.Group[],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AddAreaProps = {
|
||||||
|
name?: string,
|
||||||
|
startX: number,
|
||||||
|
startY: number,
|
||||||
|
endX: number,
|
||||||
|
endY: number
|
||||||
|
}
|
||||||
|
|
||||||
export type ProjectContextType = {
|
export type ProjectContextType = {
|
||||||
getSelectedDocument: () => ipc.Document | undefined
|
getSelectedDocument: () => ipc.Document | undefined
|
||||||
requestAddDocument: (groupId: string, documentName: string) => Promise<ipc.Document>,
|
requestAddArea: (documentId: string, area: AddAreaProps) => Promise<ipc.Area>
|
||||||
requestAddDocumentGroup: (groupName: string) => Promise<ipc.Group>,
|
requestAddDocument: (groupId: string, documentName: string) => Promise<ipc.Document>
|
||||||
selectedDocumentId: string,
|
requestAddDocumentGroup: (groupName: string) => Promise<ipc.Group>
|
||||||
setSelectedDocumentId: (id: string) => void,
|
selectedDocumentId: string
|
||||||
|
setSelectedDocumentId: (id: string) => void
|
||||||
} & ProjectProps
|
} & ProjectProps
|
||||||
2
frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts
vendored
2
frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts
vendored
@ -4,6 +4,8 @@ import {ipc} from '../models';
|
|||||||
|
|
||||||
export function GetDocuments():Promise<ipc.GetDocumentsResponse>;
|
export function GetDocuments():Promise<ipc.GetDocumentsResponse>;
|
||||||
|
|
||||||
|
export function RequestAddArea(arg1:string,arg2:ipc.Area):Promise<ipc.Area>;
|
||||||
|
|
||||||
export function RequestAddDocument(arg1:string,arg2:string):Promise<ipc.Document>;
|
export function RequestAddDocument(arg1:string,arg2:string):Promise<ipc.Document>;
|
||||||
|
|
||||||
export function RequestAddDocumentGroup(arg1:string):Promise<ipc.Group>;
|
export function RequestAddDocumentGroup(arg1:string):Promise<ipc.Group>;
|
||||||
|
|||||||
@ -6,6 +6,10 @@ export function GetDocuments() {
|
|||||||
return window['go']['ipc']['Channel']['GetDocuments']();
|
return window['go']['ipc']['Channel']['GetDocuments']();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function RequestAddArea(arg1, arg2) {
|
||||||
|
return window['go']['ipc']['Channel']['RequestAddArea'](arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
export function RequestAddDocument(arg1, arg2) {
|
export function RequestAddDocument(arg1, arg2) {
|
||||||
return window['go']['ipc']['Channel']['RequestAddDocument'](arg1, arg2);
|
return window['go']['ipc']['Channel']['RequestAddDocument'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,34 @@
|
|||||||
export namespace ipc {
|
export namespace ipc {
|
||||||
|
|
||||||
|
export class Area {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
startX: number;
|
||||||
|
startY: number;
|
||||||
|
endX: number;
|
||||||
|
endY: number;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new Area(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.id = source["id"];
|
||||||
|
this.name = source["name"];
|
||||||
|
this.startX = source["startX"];
|
||||||
|
this.startY = source["startY"];
|
||||||
|
this.endX = source["endX"];
|
||||||
|
this.endY = source["endY"];
|
||||||
|
}
|
||||||
|
}
|
||||||
export class Document {
|
export class Document {
|
||||||
id: string;
|
id: string;
|
||||||
groupId: string;
|
groupId: string;
|
||||||
name: string;
|
name: string;
|
||||||
path: string;
|
path: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
areas: Area[];
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new Document(source);
|
return new Document(source);
|
||||||
@ -18,7 +41,26 @@ export namespace ipc {
|
|||||||
this.name = source["name"];
|
this.name = source["name"];
|
||||||
this.path = source["path"];
|
this.path = source["path"];
|
||||||
this.projectId = source["projectId"];
|
this.projectId = source["projectId"];
|
||||||
|
this.areas = this.convertValues(source["areas"], Area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
if (!a) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (a.slice) {
|
||||||
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||||
|
} else if ("object" === typeof a) {
|
||||||
|
if (asMap) {
|
||||||
|
for (const key of Object.keys(a)) {
|
||||||
|
a[key] = new classs(a[key]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return new classs(a);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export class Group {
|
export class Group {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@ -23,12 +23,25 @@ func (c *Channel) GetDocuments() GetDocumentsResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range documents {
|
for _, d := range documents {
|
||||||
|
jsonAreas := make([]Area, 0)
|
||||||
|
for _, a := range d.Areas {
|
||||||
|
jsonAreas = append(jsonAreas, Area{
|
||||||
|
Id: a.Id,
|
||||||
|
Name: a.Name,
|
||||||
|
StartX: a.StartX,
|
||||||
|
StartY: a.StartY,
|
||||||
|
EndX: a.EndX,
|
||||||
|
EndY: a.EndY,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
jsonDocument := Document{
|
jsonDocument := Document{
|
||||||
Id: d.Id,
|
Id: d.Id,
|
||||||
GroupId: d.GroupId,
|
GroupId: d.GroupId,
|
||||||
Name: d.Name,
|
Name: d.Name,
|
||||||
Path: d.Path,
|
Path: d.Path,
|
||||||
ProjectId: d.ProjectId,
|
ProjectId: d.ProjectId,
|
||||||
|
Areas: jsonAreas,
|
||||||
}
|
}
|
||||||
response.Documents = append(response.Documents, jsonDocument)
|
response.Documents = append(response.Documents, jsonDocument)
|
||||||
}
|
}
|
||||||
@ -87,7 +100,7 @@ func (c *Channel) RequestAddDocumentGroup(name string) Group {
|
|||||||
newGroup := document.Group{
|
newGroup := document.Group{
|
||||||
Id: uuid.NewString(),
|
Id: uuid.NewString(),
|
||||||
Name: name,
|
Name: name,
|
||||||
ProjectId: "something else",
|
ProjectId: "something else", // TODO: change me
|
||||||
}
|
}
|
||||||
|
|
||||||
document.GetGroupCollection().AddDocumentGroup(newGroup)
|
document.GetGroupCollection().AddDocumentGroup(newGroup)
|
||||||
@ -101,3 +114,26 @@ func (c *Channel) RequestAddDocumentGroup(name string) Group {
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Channel) RequestAddArea(documentId string, area Area) Area {
|
||||||
|
runtime.LogDebug(app.GetInstance().Context, "RequestAddArea in go")
|
||||||
|
foundDocument := document.GetDocumentCollection().GetDocumentById(documentId)
|
||||||
|
|
||||||
|
var id string
|
||||||
|
if area.Id == "" {
|
||||||
|
id = uuid.NewString()
|
||||||
|
} else {
|
||||||
|
id = area.Id
|
||||||
|
}
|
||||||
|
|
||||||
|
newArea := document.Area{
|
||||||
|
Id: id,
|
||||||
|
Name: area.Name,
|
||||||
|
StartX: area.StartX,
|
||||||
|
EndX: area.EndX,
|
||||||
|
StartY: area.StartY,
|
||||||
|
EndY: area.EndY,
|
||||||
|
}
|
||||||
|
foundDocument.AddArea(newArea)
|
||||||
|
return Area(newArea)
|
||||||
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ type Document struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
ProjectId string `json:"projectId"`
|
ProjectId string `json:"projectId"`
|
||||||
|
Areas []Area `json:"areas"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DocumentCollection struct {
|
type DocumentCollection struct {
|
||||||
@ -25,3 +26,12 @@ type GroupCollection struct {
|
|||||||
Groups []Group `json:"groups"`
|
Groups []Group `json:"groups"`
|
||||||
ProjectId string `json:"projectId"`
|
ProjectId string `json:"projectId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Area struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
StartX int `json:"startX"`
|
||||||
|
StartY int `json:"startY"`
|
||||||
|
EndX int `json:"endX"`
|
||||||
|
EndY int `json:"endY"`
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user