Add Structure Class (#203)
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 38s
All checks were successful
Build Dev PWA / Build-PWA (push) Successful in 38s
This PR adds a class for detected structures and two additional classes to handle the coordinates of the bounding boxes for those structures. The classes do a better job handling conversions between image pixels, canvas pixels, and screen pixels. This means that they take the place of several chunks of the previous code such as the box2cvs function. Reviewed-on: #203
This commit is contained in:
157
src/js/structures.js
Normal file
157
src/js/structures.js
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
class Coordinate {
|
||||||
|
constructor(x, y) {
|
||||||
|
this.x = x
|
||||||
|
this.y = y
|
||||||
|
}
|
||||||
|
|
||||||
|
toRefFrame(...frameArgs) {
|
||||||
|
if (frameArgs.length == 0) {
|
||||||
|
return {x: this.x, y: this.y}
|
||||||
|
}
|
||||||
|
let outFrames = []
|
||||||
|
//Get Coordinates in Image Reference Frame
|
||||||
|
if (frameArgs[0].tagName == 'IMG' && frameArgs[0].width && frameArgs[0].height) {
|
||||||
|
outFrames.push({
|
||||||
|
x: this.x * frameArgs[0].width,
|
||||||
|
y: this.y * frameArgs[0].height
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error('Coordinate: invalid reference frame for frameType: Image')
|
||||||
|
}
|
||||||
|
//Get Coordinates in Canvas Reference Frame
|
||||||
|
if (frameArgs[1]) {
|
||||||
|
if (frameArgs[1].tagName == 'CANVAS' && frameArgs[1].width && frameArgs[1].height) {
|
||||||
|
let imgWidth
|
||||||
|
let imgHeight
|
||||||
|
const imgAspect = frameArgs[0].width / frameArgs[0].height
|
||||||
|
const rendAspect = frameArgs[1].width / frameArgs[1].height
|
||||||
|
if (imgAspect >= rendAspect) {
|
||||||
|
imgWidth = frameArgs[1].width
|
||||||
|
imgHeight = frameArgs[1].width / imgAspect
|
||||||
|
} else {
|
||||||
|
imgWidth = frameArgs[1].height * imgAspect
|
||||||
|
imgHeight = frameArgs[1].height
|
||||||
|
}
|
||||||
|
outFrames.push({
|
||||||
|
x: (frameArgs[1].width - imgWidth) / 2 + this.x * imgWidth,
|
||||||
|
y: (frameArgs[1].height - imgHeight) / 2 + this.y * imgHeight
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error('Coordinate: invalid reference frame for frameType: Canvas')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Get Coordinates in Screen Reference Frame
|
||||||
|
if (frameArgs[2]) {
|
||||||
|
if (frameArgs[2].zoom && frameArgs[2].offset && frameArgs[2].offset.x !== undefined && frameArgs[2].offset.y !== undefined) {
|
||||||
|
outFrames.push({
|
||||||
|
x: outFrames[1].x * frameArgs[2].zoom + frameArgs[2].offset.x,
|
||||||
|
y: outFrames[1].y * frameArgs[2].zoom + frameArgs[2].offset.y
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error('Coordinate: invalid reference frame for frameType: Screen')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outFrames
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return `(x: ${this.x}, y: ${this.y})`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StructureBox {
|
||||||
|
constructor(top, left, bottom, right) {
|
||||||
|
this.topLeft = new Coordinate(left, top)
|
||||||
|
this.bottomRight = new Coordinate(right, bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
getBoxes(boxType, ...frameArgs) {
|
||||||
|
let lowerH, lowerV, calcSide
|
||||||
|
switch (boxType) {
|
||||||
|
case 'point':
|
||||||
|
lowerH = 'right'
|
||||||
|
lowerV = 'bottom'
|
||||||
|
break
|
||||||
|
case 'side':
|
||||||
|
lowerH = 'width'
|
||||||
|
lowerV = 'height'
|
||||||
|
calcSide = true
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
throw new Error(`StructureBox: invalid boxType - ${boxType}`)
|
||||||
|
}
|
||||||
|
if (frameArgs.length == 0) {
|
||||||
|
return {
|
||||||
|
left: this.topLeft.x,
|
||||||
|
top: this.topLeft.y,
|
||||||
|
[lowerH]: this.bottomRight.x - ((calcSide) ? this.topLeft.x : 0),
|
||||||
|
[lowerV]: this.bottomRight.y - ((calcSide) ? this.topLeft.y : 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const tL = this.topLeft.toRefFrame(...frameArgs)
|
||||||
|
const bR = this.bottomRight.toRefFrame(...frameArgs)
|
||||||
|
let outBoxes = []
|
||||||
|
tL.forEach((cd, i) => {
|
||||||
|
outBoxes.push({
|
||||||
|
left: cd.x,
|
||||||
|
top: cd.y,
|
||||||
|
[lowerH]: bR[i].x - ((calcSide) ? cd.x : 0),
|
||||||
|
[lowerV]: bR[i].y - ((calcSide) ? cd.y : 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return outBoxes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Structure {
|
||||||
|
constructor(structResult) {
|
||||||
|
this.label = structResult.label
|
||||||
|
this.confidence = structResult.confidence
|
||||||
|
this.box = new StructureBox(
|
||||||
|
structResult.top,
|
||||||
|
structResult.left,
|
||||||
|
structResult.bottom,
|
||||||
|
structResult.right
|
||||||
|
)
|
||||||
|
this.deleted = false
|
||||||
|
this.index = -1
|
||||||
|
this.passThreshold = true
|
||||||
|
this.searched = false
|
||||||
|
}
|
||||||
|
|
||||||
|
get resultIndex() {
|
||||||
|
return this.index
|
||||||
|
}
|
||||||
|
|
||||||
|
set resultIndex(newIdx) {
|
||||||
|
this.index = newIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
get isDeleted() {
|
||||||
|
return this.deleted
|
||||||
|
}
|
||||||
|
|
||||||
|
set isDeleted(del) {
|
||||||
|
this.deleted = !!del
|
||||||
|
}
|
||||||
|
|
||||||
|
get isSearched() {
|
||||||
|
return this.searched
|
||||||
|
}
|
||||||
|
|
||||||
|
set isSearched(ser) {
|
||||||
|
this.searched = !!ser
|
||||||
|
}
|
||||||
|
|
||||||
|
get aboveThreshold() {
|
||||||
|
return this.passThreshold
|
||||||
|
}
|
||||||
|
|
||||||
|
setThreshold(level) {
|
||||||
|
if (typeof level != 'number') {
|
||||||
|
throw new Error(`Structure: invalid threshold level ${level}`)
|
||||||
|
}
|
||||||
|
this.passThreshold = this.confidence >= level
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -144,11 +144,11 @@
|
|||||||
import touchMixin from './touch-mixin'
|
import touchMixin from './touch-mixin'
|
||||||
|
|
||||||
import detectionWorker from '@/assets/detect-worker.js?worker&inline'
|
import detectionWorker from '@/assets/detect-worker.js?worker&inline'
|
||||||
|
import { Structure, StructureBox } from '../js/structures'
|
||||||
|
|
||||||
const regions = ['Thorax','Abdomen/Pelvis','Limbs','Head and Neck']
|
const regions = ['Thorax','Abdomen/Pelvis','Limbs','Head and Neck']
|
||||||
let activeRegion = 4
|
let activeRegion = 4
|
||||||
let classesList = []
|
let classesList = []
|
||||||
let imCvsLocation = {}
|
|
||||||
let imageLoadMode = "environment"
|
let imageLoadMode = "environment"
|
||||||
let serverSettings = {}
|
let serverSettings = {}
|
||||||
let otherSettings = {}
|
let otherSettings = {}
|
||||||
@@ -158,6 +158,7 @@
|
|||||||
let detectWorker = null
|
let detectWorker = null
|
||||||
let vidWorker = null
|
let vidWorker = null
|
||||||
let canvasMoving = false
|
let canvasMoving = false
|
||||||
|
let imageLocation = new StructureBox(0, 0, 1, 1)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [submitMixin, detectionMixin, cameraMixin, touchMixin],
|
mixins: [submitMixin, detectionMixin, cameraMixin, touchMixin],
|
||||||
@@ -286,14 +287,14 @@
|
|||||||
var filteredResults = this.resultData.detections
|
var filteredResults = this.resultData.detections
|
||||||
if (!filteredResults) return []
|
if (!filteredResults) return []
|
||||||
|
|
||||||
var allSelect = this.detectorLabels.every( s => { return s.detect } )
|
const allSelect = this.detectorLabels.every( s => { return s.detect } )
|
||||||
var selectedLabels = this.detectorLabels
|
const selectedLabels = this.detectorLabels
|
||||||
.filter( l => { return l.detect })
|
.filter( l => { return l.detect })
|
||||||
.map( l => { return l.name })
|
.map( l => { return l.name })
|
||||||
filteredResults.forEach( (d, i) => {
|
filteredResults.forEach( (d, i) => {
|
||||||
filteredResults[i].resultIndex = i
|
d.resultIndex = i
|
||||||
filteredResults[i].aboveThreshold = d.confidence >= this.detectorLevel
|
d.setThreshold(this.detectorLevel)
|
||||||
filteredResults[i].isSearched = allSelect || selectedLabels.includes(d.label)
|
d.isSearched = allSelect || selectedLabels.includes(d.label)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!filteredResults.some( s => s.resultIndex == this.selectedChip && s.aboveThreshold && s.isSearched && !s.isDeleted)) {
|
if (!filteredResults.some( s => s.resultIndex == this.selectedChip && s.aboveThreshold && s.isSearched && !s.isDeleted)) {
|
||||||
@@ -333,15 +334,17 @@
|
|||||||
self = this
|
self = this
|
||||||
if (eDetect.data.error) {
|
if (eDetect.data.error) {
|
||||||
self.detecting = false
|
self.detecting = false
|
||||||
self.this.resultData = {}
|
self.resultData = {}
|
||||||
loadFailure()
|
loadFailure()
|
||||||
f7.dialog.alert(`ALVINN structure finding error: ${eDetect.data.message}`)
|
f7.dialog.alert(`ALVINN structure finding error: ${eDetect.data.message}`)
|
||||||
} else if (eDetect.data.success == 'detection') {
|
} else if (eDetect.data.success == 'detection') {
|
||||||
self.detecting = false
|
self.detecting = false
|
||||||
self.resultData = eDetect.data.detections
|
self.resultData = {detections: []}
|
||||||
if (self.resultData) {
|
eDetect.data.detections.detections.forEach((d) => {
|
||||||
self.resultData.detections.map(d => {d.label = self.detectorLabels[d.label].name})
|
d.label = self.detectorLabels[d.label].name
|
||||||
}
|
let detectedStructure = new Structure(d)
|
||||||
|
self.resultData.detections.push(detectedStructure)
|
||||||
|
})
|
||||||
self.uploadDirty = true
|
self.uploadDirty = true
|
||||||
} else if (eDetect.data.success == 'model') {
|
} else if (eDetect.data.success == 'model') {
|
||||||
reloadModel = false
|
reloadModel = false
|
||||||
@@ -476,33 +479,25 @@
|
|||||||
iChip = this.selectedChip
|
iChip = this.selectedChip
|
||||||
}
|
}
|
||||||
const [imCanvas, imageCtx] = this.resetView(true)
|
const [imCanvas, imageCtx] = this.resetView(true)
|
||||||
let structLeft = this.imageView.width * this.resultData.detections[iChip].left
|
let structBox, cvsBox, screenBox
|
||||||
let structTop = this.imageView.height * this.resultData.detections[iChip].top
|
[structBox, cvsBox, screenBox] = this.resultData.detections[iChip].box.getBoxes('side', this.imageView, imCanvas, {zoom: this.canvasZoom, offset: {...this.canvasOffset}})
|
||||||
let structWidth = this.imageView.width * (this.resultData.detections[iChip].right - this.resultData.detections[iChip].left)
|
|
||||||
let structHeight = this.imageView.height * (this.resultData.detections[iChip].bottom - this.resultData.detections[iChip].top)
|
|
||||||
|
|
||||||
const boxCoords = this.box2cvs(this.resultData.detections[iChip])[0]
|
this.infoLinkPos.x = Math.min(Math.max(screenBox.left, 0),imCanvas.width)
|
||||||
|
this.infoLinkPos.y = Math.min(Math.max(screenBox.top, 0), imCanvas.height)
|
||||||
|
|
||||||
let boxLeft = boxCoords.cvsLeft
|
const imageScale = Math.max(this.imageView.width / imCanvas.width, this.imageView.height / imCanvas.height)
|
||||||
let boxTop = boxCoords.cvsTop
|
imageCtx.drawImage(this.imageView, structBox.left, structBox.top, structBox.width, structBox.height, cvsBox.left, cvsBox.top, cvsBox.width, cvsBox.height)
|
||||||
let boxWidth = boxCoords.cvsRight - boxCoords.cvsLeft
|
|
||||||
let boxHeight = boxCoords.cvsBottom - boxCoords.cvsTop
|
|
||||||
this.infoLinkPos.x = Math.min(Math.max(boxCoords.cvsLeft * this.canvasZoom + this.canvasOffset.x, 0),imCanvas.width)
|
|
||||||
this.infoLinkPos.y = Math.min(Math.max(boxCoords.cvsTop * this.canvasZoom + this.canvasOffset.y, 0), imCanvas.height)
|
|
||||||
|
|
||||||
let imageScale = Math.max(this.imageView.width / imCanvas.width, this.imageView.height / imCanvas.height)
|
|
||||||
imageCtx.drawImage(this.imageView, structLeft, structTop, structWidth, structHeight, boxLeft, boxTop, boxWidth, boxHeight)
|
|
||||||
imageCtx.save()
|
imageCtx.save()
|
||||||
imageCtx.arc(boxLeft, boxTop, 14 / this.canvasZoom, 0, 2 * Math.PI)
|
imageCtx.arc(cvsBox.left, cvsBox.top, 14 / this.canvasZoom, 0, 2 * Math.PI)
|
||||||
imageCtx.closePath()
|
imageCtx.closePath()
|
||||||
imageCtx.clip()
|
imageCtx.clip()
|
||||||
imageCtx.drawImage(this.imageView,
|
imageCtx.drawImage(this.imageView,
|
||||||
structLeft - (14 / this.canvasZoom * imageScale),
|
structBox.left - (14 / this.canvasZoom * imageScale),
|
||||||
structTop - (14 / this.canvasZoom * imageScale),
|
structBox.top - (14 / this.canvasZoom * imageScale),
|
||||||
(28 / this.canvasZoom * imageScale),
|
(28 / this.canvasZoom * imageScale),
|
||||||
(28 / this.canvasZoom * imageScale),
|
(28 / this.canvasZoom * imageScale),
|
||||||
boxLeft - (14 / this.canvasZoom),
|
cvsBox.left - (14 / this.canvasZoom),
|
||||||
boxTop - (14 / this.canvasZoom),
|
cvsBox.top - (14 / this.canvasZoom),
|
||||||
(28 / this.canvasZoom), (28 / this.canvasZoom))
|
(28 / this.canvasZoom), (28 / this.canvasZoom))
|
||||||
imageCtx.restore()
|
imageCtx.restore()
|
||||||
this.selectedChip = iChip
|
this.selectedChip = iChip
|
||||||
@@ -532,13 +527,9 @@
|
|||||||
imageCtx.strokeStyle = 'yellow'
|
imageCtx.strokeStyle = 'yellow'
|
||||||
imageCtx.lineWidth = 3 / this.canvasZoom
|
imageCtx.lineWidth = 3 / this.canvasZoom
|
||||||
if (this.imageLoaded) {
|
if (this.imageLoaded) {
|
||||||
let imageLoc = this.box2cvs({top: 0,left: 0,right: 1,bottom: 1})
|
const imageLoc = imageLocation.getBoxes('side', this.imageView, imCanvas)
|
||||||
imCvsLocation.top = imageLoc[0].cvsTop
|
|
||||||
imCvsLocation.left = imageLoc[0].cvsLeft
|
|
||||||
imCvsLocation.width = imageLoc[0].cvsRight - imageLoc[0].cvsLeft
|
|
||||||
imCvsLocation.height = imageLoc[0].cvsBottom - imageLoc[0].cvsTop
|
|
||||||
if (drawChip) {imageCtx.globalAlpha = .5}
|
if (drawChip) {imageCtx.globalAlpha = .5}
|
||||||
imageCtx.drawImage(this.imageView, 0, 0, this.imageView.width, this.imageView.height, imCvsLocation.left, imCvsLocation.top, imCvsLocation.width, imCvsLocation.height)
|
imageCtx.drawImage(this.imageView, 0, 0, this.imageView.width, this.imageView.height, imageLoc[1].left, imageLoc[1].top, imageLoc[1].width, imageLoc[1].height)
|
||||||
if (drawChip) {imageCtx.globalAlpha = 1}
|
if (drawChip) {imageCtx.globalAlpha = 1}
|
||||||
}
|
}
|
||||||
this.structureZoomed = false
|
this.structureZoomed = false
|
||||||
@@ -592,12 +583,8 @@
|
|||||||
imCanvas.width = imCanvas.clientWidth
|
imCanvas.width = imCanvas.clientWidth
|
||||||
imCanvas.height = imCanvas.clientHeight
|
imCanvas.height = imCanvas.clientHeight
|
||||||
const imageCtx = imCanvas.getContext("2d")
|
const imageCtx = imCanvas.getContext("2d")
|
||||||
let imageLoc = this.box2cvs({top: 0,left: 0,right: 1,bottom: 1})
|
const imageLoc = imageLocation.getBoxes('side', this.imageView, imCanvas)
|
||||||
imCvsLocation.top = imageLoc[0].cvsTop
|
imageCtx.drawImage(this.imageView, 0, 0, this.imageView.width, this.imageView.height, imageLoc[1].left, imageLoc[1].top, imageLoc[1].width, imageLoc[1].height)
|
||||||
imCvsLocation.left = imageLoc[0].cvsLeft
|
|
||||||
imCvsLocation.width = imageLoc[0].cvsRight - imageLoc[0].cvsLeft
|
|
||||||
imCvsLocation.height = imageLoc[0].cvsBottom - imageLoc[0].cvsTop
|
|
||||||
imageCtx.drawImage(this.imageView, 0, 0, this.imageView.width, this.imageView.height, imCvsLocation.left, imCvsLocation.top, imCvsLocation.width, imCvsLocation.height)
|
|
||||||
f7.utils.nextFrame(() => {
|
f7.utils.nextFrame(() => {
|
||||||
this.setData()
|
this.setData()
|
||||||
})
|
})
|
||||||
@@ -624,7 +611,12 @@
|
|||||||
if (li >= numBoxes) li -= numBoxes
|
if (li >= numBoxes) li -= numBoxes
|
||||||
return li
|
return li
|
||||||
}
|
}
|
||||||
let boxCoords = this.box2cvs(this.showResults)
|
let boxCoords = []
|
||||||
|
this.resultData.detections.forEach(d => {
|
||||||
|
if (d.aboveThreshold && d.isSearched && !d.isDeleted) {
|
||||||
|
boxCoords.push(d.box.getBoxes('point',this.imageView,this.$refs.image_cvs)[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
const numBoxes = boxCoords.length
|
const numBoxes = boxCoords.length
|
||||||
let clickX = (e.offsetX - this.canvasOffset.x) / this.canvasZoom
|
let clickX = (e.offsetX - this.canvasOffset.x) / this.canvasZoom
|
||||||
let clickY = (e.offsetY - this.canvasOffset.y) / this.canvasZoom
|
let clickY = (e.offsetY - this.canvasOffset.y) / this.canvasZoom
|
||||||
@@ -633,41 +625,13 @@
|
|||||||
var findBox = boxCoords.findIndex( (r, i) => {
|
var findBox = boxCoords.findIndex( (r, i) => {
|
||||||
let di = loopIndex(i)
|
let di = loopIndex(i)
|
||||||
if (di == this.selectedChip ) return false
|
if (di == this.selectedChip ) return false
|
||||||
return r.cvsLeft <= clickX &&
|
return r.left <= clickX &&
|
||||||
r.cvsRight >= clickX &&
|
r.right >= clickX &&
|
||||||
r.cvsTop <= clickY &&
|
r.top <= clickY &&
|
||||||
r.cvsBottom >= clickY &&
|
r.bottom >= clickY
|
||||||
this.resultData.detections[di].aboveThreshold &&
|
|
||||||
this.resultData.detections[di].isSearched &&
|
|
||||||
!this.resultData.detections[di].isDeleted
|
|
||||||
})
|
})
|
||||||
this.selectChip(findBox >= 0 ? this.resultData.detections[loopIndex(findBox)].resultIndex : this.selectedChip)
|
this.selectChip(findBox >= 0 ? this.resultData.detections[loopIndex(findBox)].resultIndex : this.selectedChip)
|
||||||
},
|
},
|
||||||
box2cvs(boxInput) {
|
|
||||||
if (!boxInput || boxInput.length == 0) return []
|
|
||||||
const boxList = boxInput.length ? boxInput : [boxInput]
|
|
||||||
const imCanvas = this.$refs.image_cvs
|
|
||||||
var imgWidth
|
|
||||||
var imgHeight
|
|
||||||
const imgAspect = this.imageView.width / this.imageView.height
|
|
||||||
const rendAspect = imCanvas.width / imCanvas.height
|
|
||||||
if (imgAspect >= rendAspect) {
|
|
||||||
imgWidth = imCanvas.width
|
|
||||||
imgHeight = imCanvas.width / imgAspect
|
|
||||||
} else {
|
|
||||||
imgWidth = imCanvas.height * imgAspect
|
|
||||||
imgHeight = imCanvas.height
|
|
||||||
}
|
|
||||||
const cvsCoords = boxList.map( (d, i) => {
|
|
||||||
return {
|
|
||||||
"cvsLeft": (imCanvas.width - imgWidth) / 2 + d.left * imgWidth,
|
|
||||||
"cvsRight": (imCanvas.width - imgWidth) / 2 + d.right * imgWidth,
|
|
||||||
"cvsTop": (imCanvas.height - imgHeight) / 2 + d.top * imgHeight,
|
|
||||||
"cvsBottom": (imCanvas.height - imgHeight) / 2 + d.bottom * imgHeight
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return cvsCoords
|
|
||||||
},
|
|
||||||
toggleSettings() {
|
toggleSettings() {
|
||||||
this.showDetectSettings = !this.showDetectSettings
|
this.showDetectSettings = !this.showDetectSettings
|
||||||
f7.utils.nextFrame(() => {
|
f7.utils.nextFrame(() => {
|
||||||
@@ -707,11 +671,11 @@
|
|||||||
},
|
},
|
||||||
zoomToSelected() {
|
zoomToSelected() {
|
||||||
const imCanvas = this.$refs.image_cvs
|
const imCanvas = this.$refs.image_cvs
|
||||||
const boxCoords = this.box2cvs(this.resultData.detections[this.selectedChip])[0]
|
const boxCoords = this.resultData.detections[this.selectedChip].box.getBoxes('point', this.imageView, imCanvas)
|
||||||
const boxWidth = boxCoords.cvsRight - boxCoords.cvsLeft
|
const boxWidth = boxCoords[1].right - boxCoords[1].left
|
||||||
const boxHeight = boxCoords.cvsBottom - boxCoords.cvsTop
|
const boxHeight = boxCoords[1].bottom - boxCoords[1].top
|
||||||
const boxMidX = (boxCoords.cvsRight + boxCoords.cvsLeft ) / 2
|
const boxMidX = (boxCoords[1].right + boxCoords[1].left ) / 2
|
||||||
const boxMidY = (boxCoords.cvsBottom + boxCoords.cvsTop ) / 2
|
const boxMidY = (boxCoords[1].bottom + boxCoords[1].top ) / 2
|
||||||
const zoomFactor = Math.min(imCanvas.width / boxWidth * .9, imCanvas.height / boxHeight * .9, 8)
|
const zoomFactor = Math.min(imCanvas.width / boxWidth * .9, imCanvas.height / boxHeight * .9, 8)
|
||||||
this.canvasZoom = zoomFactor
|
this.canvasZoom = zoomFactor
|
||||||
this.canvasOffset.x = -(boxMidX * zoomFactor) + imCanvas.width / 2
|
this.canvasOffset.x = -(boxMidX * zoomFactor) + imCanvas.width / 2
|
||||||
|
|||||||
Reference in New Issue
Block a user