Video.js: How to display captions only on custom TextTrackDisplay element, not on top of video - video.js

I'm attempting to display Video.js captions on a custom DOM element, outside of the video playing. This works as intended and below are snippets showing this.
Unfortunately, I can't seem to disable captions appearing also on top of the video too. Is there a way to disable captions appearing/showing on top of the video and only in the TextTrackDisplay element?
Any setting in the caption options (addRemoteTextTrack(options)) and textTrackSettings.setValues() seems to affect both on-video and custom captions.
let captionOption = {
kind: 'captions',
srclang: 'en',
label: 'English',
src: subURL,
mode: 'showing',
};
connectTextTracks = (player) => {
const TextTrackDisplay = videojs.getComponent('TextTrackDisplay');
const textTrackDisplay = new TextTrackDisplay(player);
subtitleDiv.appendChild(textTrackDisplay.el());
}
player.ready(function () {
player.addRemoteTextTrack(captionOption);
const tracks = player.remoteTextTracks();
console.log(tracks.length); // print out greater than 0 if captions exists
var settings = this.textTrackSettings;
settings.setValues({
backgroundColor: '#000',
backgroundOpacity: '1',
edgeStyle: 'uniform',
});
settings.updateDisplay();
connectTextTracks(player);
});

I ended up just hiding the on-video text track display, before creating a new TextTrackDisplay, like so:
// First hide main text track display (on-video)
const mainTextTrackDisplay = player.getChild('TextTrackDisplay');
mainTextTrackDisplay.setAttribute("hidden", true);
// Add new text track display
const TextTrackDisplay = videojs.getComponent('TextTrackDisplay');
const newTextTrackDisplay = new TextTrackDisplay(player);
const newTextTrackDisplayEl = newTextTrackDisplay.el();
// Append new text track display to subdiv element
const subDiv = document.querySelector("#subdiv");
subDiv.append(newTextTrackDisplayEl);
Full example here:
https://codepen.io/avtconnect/pen/poOvEyj

Related

HERE Maps JS API 3.1.30.17 used in VUE - Error for style group 'non-collision' in Firefox

I've build a simple Here Map using Vue 2 and the JS API in version 3.1.30.17. The map works fine in all browsers except Firefox v102.
This is the error message in Firefox:
Tangram [error]: Error for style group 'non-collision' for tile 20/7/68/41/7 CanvasRenderingContext2D.drawImage: Passed-in canvas is empty: loadTexture#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:417267
e/sn.addWorker/<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:63015
EventListener.handleEvent*e/sn.addWorker#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:62515
e/value/<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:515089
value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:515502
value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:514847
e/value/this.initializing<#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:511497
promise callback*value#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:431:511472
Ul#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:335:441
p.eh#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:378:446
p.Ge#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:329:436
p.Ge#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:376:356
S#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:369:214
T.prototype.u#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:410:166
T#https://js.api.here.com/v3/3.1.30.17/mapsjs-core.js:401:290
... The error is even bigger
The following method I'm using to init Here Maps inside Vue's mounted:
async initializeHereMap() {
const mapContainer = this.$refs.hereMap;
const H = window.H;
// Initialize the platform object:
this.platform = new H.service.Platform({
apikey: this.apiKey,
});
await this.geocode(this.platform, this.originAddress)
.then(data => this.routingParameters.origin = data[0]);
await this.geocode(this.platform, this.destinationAddress)
.then(data => this.routingParameters.destination = data[0]);
// Obtain the default map types from the platform object
const defaultLayers = this.platform.createDefaultLayers({
lg: window.navigator.language,
});
// Instantiate (and display) a map object:
const map = new H.Map(mapContainer, defaultLayers.vector.normal.map, {
zoom: this.zoom,
center: this.center,
padding: {
top: this.padding,
bottom: this.padding,
left: this.padding,
right: this.padding,
},
});
// create map pins
const mapPinOrigin = this.addMapPin('A', 40);
const mapPinDestination = this.addMapPin('B', 40);
let linestring = new H.geo.LineString();
linestring.pushPoint(this.routingParameters.origin);
linestring.pushPoint(this.routingParameters.destination);
// Create a polyline to display the route:
let routeLine = new H.map.Polyline(linestring, {
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
});
// Create a marker for the start point:
let startMarker = new H.map.Marker(this.routingParameters.origin, { icon: mapPinOrigin });
// Create a marker for the end point:
let endMarker = new H.map.Marker(this.routingParameters.destination, { icon: mapPinDestination });
// Add the route polyline and the two markers to the map:
map.addObjects([routeLine, startMarker, endMarker]);
// Set the map's viewport to make the whole route visible:
map.getViewModel().setLookAtData({bounds: routeLine.getBoundingBox()});
// add behavior control
if (this.behaviors) new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// add UI
if (this.controls) H.ui.UI.createDefault(map, defaultLayers);
},
Is there some one facing the same issue and could solved it?
Did you follow this example on: https://developer.here.com/tutorials/how-to-implement-a-web-map-using-vuejs/ ?
Tangram error is related to rendering e.g. when render map objects (like icons, markers, polylines etc.) and map vector tiles.
I don't think so that this issue related to HERE JS Map API.
Because all examples on https://developer.here.com/documentation/examples/maps-js are working well on my FireFox 102.0.1
It could be some map objects like icons or markers etc. are created in some moment but is not finished yet and then try to push onto map? Creating an icon in some asynchron function?
Or in like your code:
await this.geocode(this.platform, this.originAddress)
.then(data => this.routingParameters.origin = data[0]);
You don't know when func geocode will be finished (e.g. due slow internet connectivity)
It could be this command above is not done yet, but your code is already start to run this code:
linestring.pushPoint(this.routingParameters.origin);<-- 'this.routingParameters.origin' could be null
linestring.pushPoint(this.routingParameters.destination);
// Create a polyline to display the route:
let routeLine = new H.map.Polyline(linestring, { <-- Could cause Tangram error because 'linestring' is strange due undefined origin yet!
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
});
The polyline options is not correct in:
new H.map.Polyline(linestring, {
linestring,
style: { strokeColor: '#3F80C4', lineWidth: 5 },
}
Why in above the 'linestring' is second time in options?
Please follow correct syntax on:
https://developer.here.com/documentation/maps/3.1.31.0/api_reference/H.map.Polyline.html#.Options

How do I add custom image to mapbox marker?

const marker = document.createElement('div');
marker.innerHTML = `<img src="../../assets/FuelPin.png" style="height: 56px; width: 44px" alt=""/>`;
new mapboxgl.Marker(marker)
.setLngLat(lngLatPopup)
.addTo(this.map);
},
In the above code the src from img attribute is not loading the image. I tried using :src to bind as vue component but it is being rendered as string. My relative path to the image exists as well.
In general changing innerHTML with JavaScript is not something frameworks like Vue or React will let you do (see https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations)
Here is the plain JS example from the Mapbox GL website:
const el = document.createElement('div');
const width = marker.properties.iconSize[0];
const height = marker.properties.iconSize[1];
el.className = 'marker';
el.style.backgroundImage = `url(https://placekitten.com/g/${width}/${height}/)`;
el.style.width = `${width}px`;
el.style.height = `${height}px`;
el.style.backgroundSize = '100%';
el.addEventListener('click', () => {
window.alert(marker.properties.message);
});
// Add markers to the map.
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.addTo(map);
From https://docs.mapbox.com/mapbox-gl-js/example/custom-marker-icons/
One pro tip, if you have lots of images to load (like thousands of markers) you will get better performance if you have MapboxGL render it in WebGL vs using the DOM, for that see: https://docs.mapbox.com/mapbox-gl-js/example/add-image/

How to refresh videojs transcript area when using a playlist?

Scenario
I am using the following plugin which gets a video's captions and displays them in a transcript area:
https://github.com/walsh9/videojs-transcript
My player is based on the advanced player example (which uses playlist and playlist-ui plugins):
http://videojs.com/advanced/
Desired Behaviour
At the end of a video, the transcript area content and functionality should change to be relevant to the next videos captions.
Actual Behaviour
The transcript is working for the first video.
At the end of the video, however, the next video starts to play and the transcript area stays the same (text and functionality), and continues to use the .vtt file associated with the first video.
The captions for the second video (that are displayed in the video area) are showing correctly.
What I've Tried
I added a listener to the end of the video, clear the transcript area's html and then try and re-initialise both videojs and the transcript plugin with the following, but the transcript area is just re-populated with the same text and functionality.
// BEGIN initialize video.js and when done run initialiseTranscriptPlugin()
var my_video_id = videojs('preview-player', {}, function() {
initialiseTranscriptPlugin(this);
});
// END initialize video.js and when done run initialiseTranscriptPlugin()
// BEGIN initialise transcript plugin
function initialiseTranscriptPlugin(this_thing) {
var options = {
followPlayerTrack: true,
showTitle: false,
showTrackSelector: false,
clickArea: "text"
};
var transcript = this_thing.transcript(options);
transcript.id = "transcript_container";
var transcriptContainer = document.querySelector("#transcript_container");
transcriptContainer.appendChild(transcript.el());
}
// END initialise transcript plugin
// BEGIN events at end of video
document.getElementById('preview-player').addEventListener('ended', myHandler, false);
function myHandler(e) {
var transcriptContainer = document.querySelector("#transcript_container");
// clear contents of transcript container
transcript_container.innerHTML = "";
// BEGIN initalise video.s js again and run initialiseTranscriptPlugin()
var my_video_id = videojs('preview-player', {}, function() {
initialiseTranscriptPlugin(this);
});
// END initalise video.s js again and run initialiseTranscriptPlugin()
}
// END events at end of video
Question
How do I ensure that each video's captions are loaded in the transcript area when moving from one video to the next?
This seems to work, see this videojs-playlist event:
https://github.com/brightcove/videojs-playlist/blob/master/docs/api.md#playlistitem
// my_video_id.on('playlistitem', function() {
var test = videojs('preview-player');
var transcriptContainer = document.querySelector("#transcript_container");
transcript_container.innerHTML = "";
var options = {
followPlayerTrack: true,
showTitle: false,
showTrackSelector: false,
clickArea: "text"
};
var transcript = test.transcript(options);
transcript.id = "transcript_container";
transcriptContainer.appendChild(transcript.el());
});

Google map ignoring marker size for retina icons

I have a Google map driven by Advanced Custom Fields. I have created an iconType to dictate which icon is used as the marker depending on the custom field.
My marker images are 80px square but I want to force them to 40px square for retina reasons. I have tried lots of variations of code I've found via google etc but nothing works and the size gets ignored showing my markers at the larger 80px. My guess is because I have the 2 icons depending on iconType?
Can anyone help me force the size of these markers to 40px square please...
function add_marker( $marker, map ) {
// var
var latlng = new google.maps.LatLng( $marker.attr('data-lat'), $marker.attr('data-lng'));
var iconType = $marker.attr('data-icon');
var iconBase = '<?php echo get_template_directory_uri(); ?>/assets/';
var size = new google.maps.Size(40, 40);
if (iconType === 'Costa') {
iconName = 'costa#2x.png';
} else {
iconName = 'starbucks#2x.png';
}
// create marker
var marker = new google.maps.Marker({
position : latlng,
map : map,
clickable: false,
animation: google.maps.Animation.DROP,
icon: iconBase + iconName,
});
// add to array
map.markers.push( marker );
// if marker contains HTML, add it to an infoWindow
if( $marker.html() )
{
// create info window
var infowindow = new google.maps.InfoWindow({
content : $marker.html()
});
}
}
I did something like this recently, and I believe you'll need to use the new Icon object to specify your custom Icon properties, and use the size and scaledSize properties. I fixed my issues following this guide:
How to add retina ready pin marker to your Google maps?

Sencha how to update viewport on click on tabpanel?

I have an MVC multi item & paged image carousel in Sencha Touch 2, which works perfectly on it's own when added to the Viewport on init.
However, the problem I am having now is how to adapt it to my tab panel style app. I am a little unclear where I should put the code, at init or (I'm guessing) in the controller which fires on click of the specific tab. My tabpanel style app was downloaded from Github (Sencha touch 2 boilerplate template).
My working MVC carousel calls the following in the app.js:
controllers: ['Main'],
views: ['Carousel', 'Page'],
stores: ['Thumbnails'],
models: ['Thumbnail'],
launch: function () {
var carousel = Ext.create('Ext.Carousel');
Ext.Viewport.add(carousel);
Ext.getStore('Thumbnails').load(function (apps) {
var cols = 4, rows = 4; // todo: change for tablets
var page;
var btn;
var iPage = 0;
var iApp = 0;
var x = 1, y = 1, z = 0;
var row, grid, bottomrow;
var firstpage = 0;
etc....code cut for readbility.
Basically I want this carousel to appear on the second tab of the tabpanel, not initially on the viewport how it works now. Perhaps I should have the working launch code in a controller that fires when I'm on that tab of the tabpanel? I'm not sure of the best way to approach this.
Here is the launch function of my tabpanel app, with the
launch: function() {
Ext.create('TCApp.view.Viewport', {fullscreen: true});
// I have tried adding this working launch code after creating the Viewport, but maybe it should be in the controller? But I'm not sure how to go about it...
var carousel = Ext.create('Ext.Carousel');
Ext.Viewport.add(carousel);
Ext.getStore('Thumbnails').load(function (apps) {
var cols = 4, rows = 4; // todo: change for tablets
var page;
var btn;
var iPage = 0;
var iApp = 0;
var x = 1, y = 1, z = 0;
var row, grid, bottomrow;
var firstpage = 0;
Any help would be much appreciated!
You are adding your carousel to Ext.Viewport, which is the component that gets instantiated by default on application bootstrap. So, instead of using Ext.Viewport.add(carousel);, and adding it to the Viewport itself, try with
tabpanel.add(carousel);
Where tabpanel is the reference to your tab panel instance. This way you'll be adding the carousel to the first available card in Ext.tab.Panel
Thanks Grgur, it helped. I eventually solved it this way, making sure to have a title and iconCls otherwise I get an error in the console when adding the carousel item to the tabpanel:
var carousel = Ext.create('Ext.Carousel', {
title: 'Carousel',
iconCls: 'info'
});
var MyTabPanel = Ext.getCmp('mytabpanel');
MyTabPanel.add(carousel);