Commit a20dd55b authored by 朱松文's avatar 朱松文

动态跟踪实现

parent 2defcd63
import { DogTrackData } from "../MyVideo/data";
export interface DogData {
id: number;
videoUrl: string;
picture: string;
beginTime: string;
endTime: string;
......@@ -7,4 +10,5 @@ export interface DogData {
isHand: boolean;
dogType: string;
hairColor: string;
trackData?: DogTrackData[];
}
......@@ -81,7 +81,8 @@ export default class DogInfo extends BaseVue {
@Prop() private dog: DogData;
play(): void {
console.log("play");
console.log("aaa", this.dog);
this.$emit("play", this.dog);
}
}
</script>
......
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
<template>
<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>
</video>
</template>
<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 videojs from "video.js";
import "@/components/MyVideo/track/index";
import "@/assets/scss/myVideo.scss";
import { TrackData } from "./data";
@Component({})
export default class MyVideo extends Vue {
@Prop() private src!: string;
@Prop() private width!: number;
@Prop() private trackData!: TrackData[];
player = null;
videoUrl = "";
dogTrack = null;
mounted() {
this.videoUrl = this.src;
const _this = this;
this.$nextTick(() => {
this.player = videojs(
"najiu-player",
......@@ -29,13 +35,26 @@ export default class MyVideo extends Vue {
width: this.width,
},
function onPlayerReady() {
console.log("ready", this);
//@ts-ignore
this.addChild("DogTrack");
console.log("**", _this.trackData);
_this.dogTrack = this.getChild("DogTrack");
_this.dogTrack.initData(_this.trackData);
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() {
......
import videojs from 'video.js'
import { TrackData } from "../data"
const Component = videojs.getComponent('Component');
......@@ -9,16 +10,59 @@ class DogTrack extends Component {
player.on("timeupdate", (e) => this.update(e))
}
trackData = [] //传入初始数组
trackingData = []//正在跟踪的数组
trackedData = []//已经被跟踪过的数组
processing = false//是否在处理中
myel = undefined
createEl(): HTMLDivElement {
const el = document.createElement("div")
el.id = "trackDiv"
el.classList.add("najiu-dog-track")
return el;
}
update(e) {
//@ts-ignore
console.log("update", this.player_.currentTime())
if (this.processing || this.trackingData.length === 0 || !this.myel) return
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)
}
}
......
......@@ -35,6 +35,15 @@ export default {
hairColor: "黑白相间",
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",
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,
......@@ -46,6 +55,16 @@ export default {
hairColor: "黑色",
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",
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,
......@@ -57,6 +76,7 @@ export default {
hairColor: "黑色",
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",
videoUrl: "//vjs.zencdn.net/v/oceans.mp4"
},
{
id: 4,
......@@ -68,6 +88,7 @@ export default {
hairColor: "黑色",
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",
videoUrl: "http://skynet-test.inajiu.com:7011/sn-web/video/video"
},
{
id: 5,
......@@ -79,6 +100,7 @@ export default {
hairColor: "黑色",
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",
videoUrl: "//vjs.zencdn.net/v/oceans.mp4"
},
],
};
\ No newline at end of file
/**
* @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;
};
/**
* @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;
}
......@@ -11,16 +11,12 @@
</div>
</div>
<div class="player" ref="player-container">
<MyVideo
v-if="width > 0"
src="http://skynet-test.inajiu.com:7011/sn-web/video/video"
:width="width"
/>
<MyVideo v-if="width > 0 && videoUrl" :src="videoUrl" :trackData="trackData" :width="width" />
</div>
<div class="video-list">
<div class="title">犬只记录</div>
<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>
......@@ -35,6 +31,9 @@ import Search from "@/components/Camera/search.vue";
import BaseVue from "@/types/baseVue";
import MyVideo from "@/components/MyVideo/index.vue";
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 } })
export default class Dashboard extends BaseVue {
......@@ -43,6 +42,8 @@ export default class Dashboard extends BaseVue {
}
width = 0;
height = 0;
videoUrl = "";
trackData: TrackData[] = [];
mounted() {
this.$nextTick(() => {
const p = this.$refs["player-container"];
......@@ -50,9 +51,17 @@ export default class Dashboard extends BaseVue {
this.width = p.offsetWidth;
//@ts-ignore
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>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment