Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
najiu-skynet-admin
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
najiu-frontend
najiu-skynet-admin
Commits
a20dd55b
Commit
a20dd55b
authored
Sep 22, 2021
by
朱松文
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
动态跟踪实现
parent
2defcd63
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
308 additions
and
13 deletions
+308
-13
data.d.ts
src/components/DogInfo/data.d.ts
+4
-0
index.vue
src/components/DogInfo/index.vue
+2
-1
data.d.ts
src/components/MyVideo/data.d.ts
+23
-0
index.vue
src/components/MyVideo/index.vue
+22
-3
index.ts
src/components/MyVideo/track/index.ts
+46
-2
cameraData.ts
src/mock/cameraData.ts
+22
-0
fn.ts
src/utils/fn.ts
+137
-0
guid.ts
src/utils/guid.ts
+36
-0
index.vue
src/views/dashboard/index.vue
+16
-7
No files found.
src/components/DogInfo/data.d.ts
View file @
a20dd55b
import
{
DogTrackData
}
from
"
../MyVideo/data
"
;
export
interface
DogData
{
export
interface
DogData
{
id
:
number
;
id
:
number
;
videoUrl
:
string
;
picture
:
string
;
picture
:
string
;
beginTime
:
string
;
beginTime
:
string
;
endTime
:
string
;
endTime
:
string
;
...
@@ -7,4 +10,5 @@ export interface DogData {
...
@@ -7,4 +10,5 @@ export interface DogData {
isHand
:
boolean
;
isHand
:
boolean
;
dogType
:
string
;
dogType
:
string
;
hairColor
:
string
;
hairColor
:
string
;
trackData
?:
DogTrackData
[];
}
}
src/components/DogInfo/index.vue
View file @
a20dd55b
...
@@ -81,7 +81,8 @@ export default class DogInfo extends BaseVue {
...
@@ -81,7 +81,8 @@ export default class DogInfo extends BaseVue {
@
Prop
()
private
dog
:
DogData
;
@
Prop
()
private
dog
:
DogData
;
play
():
void
{
play
():
void
{
console
.
log
(
"
play
"
);
console
.
log
(
"
aaa
"
,
this
.
dog
);
this
.
$emit
(
"
play
"
,
this
.
dog
);
}
}
}
}
</
script
>
</
script
>
...
...
src/components/MyVideo/data.d.ts
0 → 100644
View file @
a20dd55b
export
interface
TrackData
{
time
:
number
,
position
:
PostitionData
,
shape
:
Shape
,
videoShape
?:
VideoShape
,
beginTime
?:
number
,
endTime
?:
number
}
export
interface
PostitionData
{
top
:
number
,
left
:
number
}
export
interface
Shape
{
width
:
number
,
height
:
number
}
export
interface
VideoShape
{
width
:
number
,
height
:
number
}
\ No newline at end of file
src/components/MyVideo/index.vue
View file @
a20dd55b
<
template
>
<
template
>
<video
id=
"najiu-player"
class=
"video-js"
muted
preload=
"auto"
>
<video
id=
"najiu-player"
class=
"video-js"
muted
preload=
"auto"
>
<source
:src=
"
src
"
type=
"video/mp4"
/>
<source
:src=
"
videoUrl
"
type=
"video/mp4"
/>
<p
class=
"vjs-no-js"
>
当前浏览器不支持视频播放
</p>
<p
class=
"vjs-no-js"
>
当前浏览器不支持视频播放
</p>
</video>
</video>
</
template
>
</
template
>
<
script
lang=
"ts"
>
<
script
lang=
"ts"
>
import
{
Component
,
Vue
,
Prop
}
from
"
vue-property-decorator
"
;
import
{
Component
,
Vue
,
Prop
,
Watch
}
from
"
vue-property-decorator
"
;
import
"
video.js/dist/video-js.min.css
"
;
import
"
video.js/dist/video-js.min.css
"
;
import
videojs
from
"
video.js
"
;
import
videojs
from
"
video.js
"
;
import
"
@/components/MyVideo/track/index
"
;
import
"
@/components/MyVideo/track/index
"
;
import
"
@/assets/scss/myVideo.scss
"
;
import
"
@/assets/scss/myVideo.scss
"
;
import
{
TrackData
}
from
"
./data
"
;
@
Component
({})
@
Component
({})
export
default
class
MyVideo
extends
Vue
{
export
default
class
MyVideo
extends
Vue
{
@
Prop
()
private
src
!
:
string
;
@
Prop
()
private
src
!
:
string
;
@
Prop
()
private
width
!
:
number
;
@
Prop
()
private
width
!
:
number
;
@
Prop
()
private
trackData
!
:
TrackData
[];
player
=
null
;
player
=
null
;
videoUrl
=
""
;
dogTrack
=
null
;
mounted
()
{
mounted
()
{
this
.
videoUrl
=
this
.
src
;
const
_this
=
this
;
this
.
$nextTick
(()
=>
{
this
.
$nextTick
(()
=>
{
this
.
player
=
videojs
(
this
.
player
=
videojs
(
"
najiu-player
"
,
"
najiu-player
"
,
...
@@ -29,13 +35,26 @@ export default class MyVideo extends Vue {
...
@@ -29,13 +35,26 @@ export default class MyVideo extends Vue {
width
:
this
.
width
,
width
:
this
.
width
,
},
},
function
onPlayerReady
()
{
function
onPlayerReady
()
{
console
.
log
(
"
ready
"
,
this
);
//@ts-ignore
//@ts-ignore
this
.
addChild
(
"
DogTrack
"
);
this
.
addChild
(
"
DogTrack
"
);
console
.
log
(
"
**
"
,
_this
.
trackData
);
_this
.
dogTrack
=
this
.
getChild
(
"
DogTrack
"
);
_this
.
dogTrack
.
initData
(
_this
.
trackData
);
this
.
play
();
this
.
play
();
}
}
);
);
});
});
//监听play方法
this
.
$emit
(
"
play
"
);
}
@
Watch
(
"
src
"
)
onSrcChange
(
newValue
:
string
,
oldValue
:
string
)
{
if
(
oldValue
===
newValue
)
return
;
this
.
dogTrack
.
initData
(
this
.
trackData
);
this
.
videoUrl
=
newValue
;
this
.
player
.
src
(
newValue
);
this
.
player
.
play
();
}
}
beforeDestroy
()
{
beforeDestroy
()
{
...
...
src/components/MyVideo/track/index.ts
View file @
a20dd55b
import
videojs
from
'
video.js
'
import
videojs
from
'
video.js
'
import
{
TrackData
}
from
"
../data
"
const
Component
=
videojs
.
getComponent
(
'
Component
'
);
const
Component
=
videojs
.
getComponent
(
'
Component
'
);
...
@@ -9,16 +10,59 @@ class DogTrack extends Component {
...
@@ -9,16 +10,59 @@ class DogTrack extends Component {
player
.
on
(
"
timeupdate
"
,
(
e
)
=>
this
.
update
(
e
))
player
.
on
(
"
timeupdate
"
,
(
e
)
=>
this
.
update
(
e
))
}
}
trackData
=
[]
//传入初始数组
trackingData
=
[]
//正在跟踪的数组
trackedData
=
[]
//已经被跟踪过的数组
processing
=
false
//是否在处理中
myel
=
undefined
createEl
():
HTMLDivElement
{
createEl
():
HTMLDivElement
{
const
el
=
document
.
createElement
(
"
div
"
)
const
el
=
document
.
createElement
(
"
div
"
)
el
.
id
=
"
trackDiv
"
el
.
classList
.
add
(
"
najiu-dog-track
"
)
el
.
classList
.
add
(
"
najiu-dog-track
"
)
return
el
;
return
el
;
}
}
update
(
e
)
{
update
(
e
)
{
//@ts-ignore
if
(
this
.
processing
||
this
.
trackingData
.
length
===
0
||
!
this
.
myel
)
return
console
.
log
(
"
update
"
,
this
.
player_
.
currentTime
())
this
.
processing
=
true
const
currentTime
=
this
.
player_
.
currentTime
()
*
1000
for
(
let
i
=
0
;
i
<
this
.
trackingData
.
length
;
i
++
)
{
const
d
=
this
.
trackingData
[
i
]
if
(
currentTime
>
d
.
beginTime
&&
currentTime
<
d
.
endTime
)
{
this
.
myel
.
style
.
top
=
`
${
d
.
position
.
top
}
%`
this
.
myel
.
style
.
left
=
`
${
d
.
position
.
left
}
%`
this
.
trackedData
.
push
(...
this
.
trackingData
.
splice
(
0
,
i
+
1
))
break
;
}
}
this
.
processing
=
false
}
initData
(
data
:
TrackData
[])
{
this
.
myel
=
document
.
getElementById
(
"
trackDiv
"
)
if
(
!
data
||
data
.
length
===
0
)
{
this
.
trackData
=
[]
return
}
}
let
pre
;
this
.
trackData
=
data
.
map
((
d
:
TrackData
)
=>
{
if
(
!
pre
)
{
d
.
beginTime
=
0
;
d
.
endTime
=
d
.
time
;
}
else
{
d
.
beginTime
=
pre
.
endTime
;
d
.
endTime
=
d
.
time
}
pre
=
d
this
.
trackingData
.
push
(
d
)
return
d
})
console
.
log
(
"
data
"
,
this
.
trackData
,
this
.
trackingData
)
}
}
}
...
...
src/mock/cameraData.ts
View file @
a20dd55b
...
@@ -35,6 +35,15 @@ export default {
...
@@ -35,6 +35,15 @@ export default {
hairColor
:
"
黑白相间
"
,
hairColor
:
"
黑白相间
"
,
picture
:
picture
:
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u283.png
"
,
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u283.png
"
,
videoUrl
:
"
http://skynet-test.inajiu.com:7011/sn-web/video/video
"
,
trackData
:
[
{
time
:
500
,
position
:
{
top
:
15
,
left
:
15
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
1000
,
position
:
{
top
:
20
,
left
:
20
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
1500
,
position
:
{
top
:
25
,
left
:
25
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
2000
,
position
:
{
top
:
30
,
left
:
30
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
2500
,
position
:
{
top
:
35
,
left
:
35
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
3000
,
position
:
{
top
:
40
,
left
:
40
},
shape
:
{
width
:
45
,
height
:
95
}
},
]
},
},
{
{
id
:
2
,
id
:
2
,
...
@@ -46,6 +55,16 @@ export default {
...
@@ -46,6 +55,16 @@ export default {
hairColor
:
"
黑色
"
,
hairColor
:
"
黑色
"
,
picture
:
picture
:
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u301.png
"
,
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u301.png
"
,
videoUrl
:
"
//vjs.zencdn.net/v/oceans.mp4
"
,
trackData
:
[
{
time
:
500
,
position
:
{
top
:
15
,
left
:
15
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
1000
,
position
:
{
top
:
20
,
left
:
20
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
1500
,
position
:
{
top
:
25
,
left
:
25
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
2000
,
position
:
{
top
:
30
,
left
:
30
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
2500
,
position
:
{
top
:
35
,
left
:
35
},
shape
:
{
width
:
45
,
height
:
95
}
},
{
time
:
3000
,
position
:
{
top
:
40
,
left
:
40
},
shape
:
{
width
:
45
,
height
:
95
}
},
]
},
},
{
{
id
:
3
,
id
:
3
,
...
@@ -57,6 +76,7 @@ export default {
...
@@ -57,6 +76,7 @@ export default {
hairColor
:
"
黑色
"
,
hairColor
:
"
黑色
"
,
picture
:
picture
:
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u319.png
"
,
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u319.png
"
,
videoUrl
:
"
//vjs.zencdn.net/v/oceans.mp4
"
},
},
{
{
id
:
4
,
id
:
4
,
...
@@ -68,6 +88,7 @@ export default {
...
@@ -68,6 +88,7 @@ export default {
hairColor
:
"
黑色
"
,
hairColor
:
"
黑色
"
,
picture
:
picture
:
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u337.png
"
,
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u337.png
"
,
videoUrl
:
"
http://skynet-test.inajiu.com:7011/sn-web/video/video
"
},
},
{
{
id
:
5
,
id
:
5
,
...
@@ -79,6 +100,7 @@ export default {
...
@@ -79,6 +100,7 @@ export default {
hairColor
:
"
黑色
"
,
hairColor
:
"
黑色
"
,
picture
:
picture
:
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u355.png
"
,
"
http://10.2.100.131/tianwang/images/%E8%A7%86%E9%A2%91%E7%BB%93%E6%9E%84%E5%8C%96/u355.png
"
,
videoUrl
:
"
//vjs.zencdn.net/v/oceans.mp4
"
},
},
],
],
};
};
\ No newline at end of file
src/utils/fn.ts
0 → 100644
View file @
a20dd55b
/**
* @file fn.js
* @module fn
*/
import
{
newGUID
}
from
'
./guid.js
'
;
import
window
from
'
global/window
'
;
export
const
UPDATE_REFRESH_INTERVAL
=
30
;
/**
* Bind (a.k.a proxy or context). A simple method for changing the context of
* a function.
*
* It also stores a unique id on the function so it can be easily removed from
* events.
*
* @function
* @param {Mixed} context
* The object to bind as scope.
*
* @param {Function} fn
* The function to be bound to a scope.
*
* @param {number} [uid]
* An optional unique ID for the function to be set
*
* @return {Function}
* The new function that will be bound into the context given
*/
export
const
bind
=
function
(
context
,
fn
,
uid
)
{
// Make sure the function has a unique ID
if
(
!
fn
.
guid
)
{
fn
.
guid
=
newGUID
();
}
// Create the new function that changes the context
const
bound
=
fn
.
bind
(
context
);
// Allow for the ability to individualize this function
// Needed in the case where multiple objects might share the same prototype
// IF both items add an event listener with the same function, then you try to remove just one
// it will remove both because they both have the same guid.
// when using this, you need to use the bind method when you remove the listener as well.
// currently used in text tracks
bound
.
guid
=
(
uid
)
?
uid
+
'
_
'
+
fn
.
guid
:
fn
.
guid
;
return
bound
;
};
/**
* Wraps the given function, `fn`, with a new function that only invokes `fn`
* at most once per every `wait` milliseconds.
*
* @function
* @param {Function} fn
* The function to be throttled.
*
* @param {number} wait
* The number of milliseconds by which to throttle.
*
* @return {Function}
*/
export
const
throttle
=
function
(
fn
,
wait
)
{
let
last
=
window
.
performance
.
now
();
const
throttled
=
function
(...
args
)
{
const
now
=
window
.
performance
.
now
();
if
(
now
-
last
>=
wait
)
{
fn
(...
args
);
last
=
now
;
}
};
return
throttled
;
};
/**
* Creates a debounced function that delays invoking `func` until after `wait`
* milliseconds have elapsed since the last time the debounced function was
* invoked.
*
* Inspired by lodash and underscore implementations.
*
* @function
* @param {Function} func
* The function to wrap with debounce behavior.
*
* @param {number} wait
* The number of milliseconds to wait after the last invocation.
*
* @param {boolean} [immediate]
* Whether or not to invoke the function immediately upon creation.
*
* @param {Object} [context=window]
* The "context" in which the debounced function should debounce. For
* example, if this function should be tied to a Video.js player,
* the player can be passed here. Alternatively, defaults to the
* global `window` object.
*
* @return {Function}
* A debounced function.
*/
export
const
debounce
=
function
(
func
,
wait
,
immediate
,
context
=
window
)
{
let
timeout
;
const
cancel
=
()
=>
{
context
.
clearTimeout
(
timeout
);
timeout
=
null
;
};
/* eslint-disable consistent-this */
const
debounced
=
function
(...
args
:
any
[])
{
const
self
=
this
;
// const args = arguments;
let
later
=
function
()
{
timeout
=
null
;
later
=
null
;
if
(
!
immediate
)
{
func
.
apply
(
self
,
args
);
}
};
if
(
!
timeout
&&
immediate
)
{
func
.
apply
(
self
,
args
);
}
context
.
clearTimeout
(
timeout
);
timeout
=
context
.
setTimeout
(
later
,
wait
);
};
/* eslint-enable consistent-this */
debounced
.
cancel
=
cancel
;
return
debounced
;
};
src/utils/guid.ts
0 → 100644
View file @
a20dd55b
/**
* @file guid.js
* @module guid
*/
// Default value for GUIDs. This allows us to reset the GUID counter in tests.
//
// The initial GUID is 3 because some users have come to rely on the first
// default player ID ending up as `vjs_video_3`.
//
// See: https://github.com/videojs/video.js/pull/6216
const
_initialGuid
=
3
;
/**
* Unique ID for an element or function
*
* @type {Number}
*/
let
_guid
=
_initialGuid
;
/**
* Get a unique auto-incrementing ID by number that has not been returned before.
*
* @return {number}
* A new unique ID.
*/
export
function
newGUID
()
{
return
_guid
++
;
}
/**
* Reset the unique auto-incrementing ID for testing only.
*/
export
function
resetGuidInTestsOnly
()
{
_guid
=
_initialGuid
;
}
src/views/dashboard/index.vue
View file @
a20dd55b
...
@@ -11,16 +11,12 @@
...
@@ -11,16 +11,12 @@
</div>
</div>
</div>
</div>
<div
class=
"player"
ref=
"player-container"
>
<div
class=
"player"
ref=
"player-container"
>
<MyVideo
<MyVideo
v-if=
"width > 0 && videoUrl"
:src=
"videoUrl"
:trackData=
"trackData"
:width=
"width"
/>
v-if=
"width > 0"
src=
"http://skynet-test.inajiu.com:7011/sn-web/video/video"
:width=
"width"
/>
</div>
</div>
<div
class=
"video-list"
>
<div
class=
"video-list"
>
<div
class=
"title"
>
犬只记录
</div>
<div
class=
"title"
>
犬只记录
</div>
<div
class=
"detail"
>
<div
class=
"detail"
>
<DogInfo
v-for=
"(dog, i) in dogData"
:key=
"i"
:dog=
"dog"
/>
<DogInfo
@
play=
"handlePlay"
v-for=
"(dog, i) in dogData"
:key=
"i"
:dog=
"dog"
/>
</div>
</div>
</div>
</div>
</div>
</div>
...
@@ -35,6 +31,9 @@ import Search from "@/components/Camera/search.vue";
...
@@ -35,6 +31,9 @@ import Search from "@/components/Camera/search.vue";
import
BaseVue
from
"
@/types/baseVue
"
;
import
BaseVue
from
"
@/types/baseVue
"
;
import
MyVideo
from
"
@/components/MyVideo/index.vue
"
;
import
MyVideo
from
"
@/components/MyVideo/index.vue
"
;
import
CameraData
from
"
@/mock/cameraData
"
;
import
CameraData
from
"
@/mock/cameraData
"
;
import
{
DogData
}
from
"
@/components/DogInfo/data
"
;
import
{
TrackData
}
from
"
@/components/MyVideo/data
"
;
import
cameraData
from
"
@/mock/cameraData
"
;
@
Component
({
components
:
{
Camera
,
DogInfo
,
Search
,
MyVideo
}
})
@
Component
({
components
:
{
Camera
,
DogInfo
,
Search
,
MyVideo
}
})
export
default
class
Dashboard
extends
BaseVue
{
export
default
class
Dashboard
extends
BaseVue
{
...
@@ -43,6 +42,8 @@ export default class Dashboard extends BaseVue {
...
@@ -43,6 +42,8 @@ export default class Dashboard extends BaseVue {
}
}
width
=
0
;
width
=
0
;
height
=
0
;
height
=
0
;
videoUrl
=
""
;
trackData
:
TrackData
[]
=
[];
mounted
()
{
mounted
()
{
this
.
$nextTick
(()
=>
{
this
.
$nextTick
(()
=>
{
const
p
=
this
.
$refs
[
"
player-container
"
];
const
p
=
this
.
$refs
[
"
player-container
"
];
...
@@ -50,9 +51,17 @@ export default class Dashboard extends BaseVue {
...
@@ -50,9 +51,17 @@ export default class Dashboard extends BaseVue {
this
.
width
=
p
.
offsetWidth
;
this
.
width
=
p
.
offsetWidth
;
//@ts-ignore
//@ts-ignore
this
.
height
=
p
.
offsetHeight
;
this
.
height
=
p
.
offsetHeight
;
console
.
log
(
"
&&&&
"
,
p
,
this
.
width
,
this
.
height
);
//todo:
this
.
videoUrl
=
CameraData
.
dogData
[
0
].
videoUrl
;
this
.
trackData
=
cameraData
.
dogData
[
0
].
trackData
;
});
});
}
}
handlePlay
(
dog
:
DogData
):
void
{
this
.
videoUrl
=
dog
.
videoUrl
;
this
.
trackData
=
dog
.
trackData
;
console
.
log
(
"
dog
"
,
this
.
videoUrl
,
this
.
trackData
);
}
}
}
</
script
>
</
script
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment