【问题标题】:Why image src is not updating even using property binding [src]?为什么即使使用属性绑定 [src],图像 src 也不会更新?
【发布时间】:2019-12-19 16:38:10
【问题描述】:

我正在尝试使用 getDisplayMedia() 捕获屏幕(我使用外部 js 来使用 getDisplayMedia(),因为我猜 angular 4 不支持它)。在第一次点击事件时,它会显示准确的截图图像,但之后它不会从第二次点击事件开始更新图像。

我试过了:

  • 要使用更新src 创建动态元素,但bypassSecurityTrustUrl() 需要将src 绑定为属性。即[src]="screenshot"。所以我想我不能在动态元素创建中做到这一点。
  • 在点击事件发生时首先清除画布和图像src。 另请注意,资源链接是基于 base64 的 URL。

app.component.ts

import { Component, HostListener } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';
import { TranslateService } from '@ngx-translate/core';
import { DomSanitizer, SafeResourceUrl, SafeUrl } from '@angular/platform-browser';
import { NotificationService } from './primary/services/notification.service';
import { AppConstants } from './shared/AppConstants';
import { CookieService } from './primary/services/cookie-service';
import {DialogboxService} from './primary/services/dialogbox.service';

//Core javascript classes.
declare var MediaRecorder: any;
declare var getStream: any;

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // _navigator:any = null;
  displayPopup: boolean = false;
  msgs: any;
  subscription: Subscription;
  flag: any;
  stream = null;
  shadowRoot = null;
  videoplayer = null;
  chunks = [];
  mediaRecorder = null;
  status = 'Inactive';
  recording = null;
  screenshot = null;
  validNavigation = 0;
  contx = null;
  canvas = null;

  constructor(public notifyer: NotificationService, private translate: TranslateService,
              public _cookieService:CookieService, private dialogboxService:DialogboxService,
              private sanitizer: DomSanitizer) {

    AppConstants.LANGUAGE = 'en';
    translate.setDefaultLang(AppConstants.LANGUAGE);
    translate.use(AppConstants.LANGUAGE);
    this.subscription = this.notifyer.notificationChange
      .subscribe(msgs => {
        this.msgs = msgs;
      });
  }

  ngOnInit(){
    this.videoplayer = document.getElementById("invisibleVideo")
    this.canvas = document.getElementById("myCanvas");
    this.canvas.width = window.innerWidth; //document.width is obsolete
    this.canvas.height = window.innerHeight;
  }

  //to take timeout
  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  async _takeScreenshot(){
    this.stream = await getStream();
    this.mediaRecorder = new MediaRecorder(this.stream, {mimeType: 'video/webm'});
    this.mediaRecorder.addEventListener('dataavailable', event => {
      if (event.data && event.data.size > 0) {
        this.chunks.push(event.data);
      }
    });
    this.mediaRecorder.start(100);
    await this.sleep(1200);
    this.mediaRecorder.stop();
    this.mediaRecorder = null;
    this.stream.getTracks().forEach(track => track.stop());
    this.stream = null;
    //allow dynamic source base64 URL
    this.recording = this.sanitizer.bypassSecurityTrustUrl(window.URL.createObjectURL(new Blob(this.chunks, {type: 'video/webm'})));
    await this.sleep(600);
    this.contx = this.canvas.getContext("2d")
    this.contx.drawImage(this.videoplayer,0,0)
    //allow dynamic source base64 URL
    this.screenshot = this.sanitizer.bypassSecurityTrustUrl(this.canvas.toDataURL('image/png'))
    this.canvas.width = window.innerWidth; //document.width is obsolete
    this.canvas.height = window.innerHeight;
    this.displayPopup = true;
  }

  takeSelfie(){
    this._takeScreenshot();
  }
}

app.component.html

<script src="../assets/adapter.js"></script>
<style>
  video {
    --video-width: 100%;
    width: var(--video-width);
    height: calc(var(--video-width) * (16 / 9));
  }
</style>
<p-dialog [positionTop]="40" (onHide)="displayPopup=false" [styleClass]="'popup_width'"
  header='Report Bug' [(visible)]="displayPopup" modal="modal" [responsive]="true">
  <div id="ssDiv">
    <img [src]="screenshot" id="ssImg" class="ssImg">
  </div>
  <div id="container">
    <canvas id="myCanvas"></canvas>
    <div id="vDiv">
      <video style="display:none" controls="true" id="invisibleVideo" playsinline
              autoplay loop muted [src]="recording ? recording : ''"></video>
    </div>
  </div>
  </p-dialog>
<button class="report-bug-button" (click)="takeSelfie()">
  <i class="fa fa-camera" aria-hidden="true" style="color:white;font-size: 25px;"></i>
</button>

adapter.js

var getStream = function getStream(){
  if (navigator.getDisplayMedia) {
    return navigator.getDisplayMedia({video: true});
  } else if (navigator.mediaDevices.getDisplayMedia) {
    return navigator.mediaDevices.getDisplayMedia({video: true});
  } else {
    return navigator.mediaDevices.getUserMedia({video: {mediaSource: 'screen'}});
  }
}

我希望每次点击事件发生时,图像都应该更新为新的屏幕截图,而不是停留在旧屏幕上。

【问题讨论】:

  • 您可以尝试将值设置为null,然后在_takeScreenshot 方法中为screenshot 分配新值。
  • 是的!我也试过这个。

标签: angular async-await html5-canvas


【解决方案1】:

新记录的屏幕数据块被追加到数组中。 this.chunks.push(event.data);

每当视频播放器开始播放录制内容时,它总是从开始时录制的内容开始。因此,屏幕截图始终是从初始帧中截取的。这是实际的错误。 解决方案是清除 _takeScreenshot 中的块数组。

this.chunks = []

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-08
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 2014-10-24
    相关资源
    最近更新 更多