Twilio Video Call issue on iOS Safari, After call start video freeze nodejs issue - ios

I have created a video call application using Nodejs & Twilio CLI. And using this in my both mobile app Android & iOS. On Android is working perfectly. But on iOS, there is an issue, when users reach the video call page, it's showing preview but as the user clicks on the Join Room button, then his/her video stops and just showing a black screen. While he can talk with other users and can see the video of them. And the Second user also can see his/her video perfectly. Only the issue he/she can't see his/her video on that call.
My html code
<!DOCTYPE html>
<html>
<head>
<style>
.joinbtn {
border: none;
padding: 10px 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 4px 2px;
cursor: pointer;
background-color: #2b96cc;
color: #fff;
}
.stvbtn {
border: none;
padding: 10px 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 4px 2px;
cursor: pointer;
background-color: #2b96cc;
color: #fff;
}
.endbtn {
float:right;
border: none;
padding: 10px 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 4px 2px;
cursor: pointer;
background-color: #dc3545;
color: #fff;
}
#media screen and (max-width: 820px) {
video {
object-fit: cover;
width: 100%;
height: 47vh;
}
}
#media screen and (min-width: 821px){
video {
object-fit: contain;
}
}
.connect_btn{
display: flex;
justify-content: center;
align-content: space-around;
margin-top: -50px;
opacity: 0.8;
padding-bottom:8px;
}
button.endbtn:disabled, button.joinbtn:disabled {
background-color: #607d8b;
color: #ffffff;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/webrtc-adapter/6.4.0/adapter.js" type="text/javascript"></script>
<script src="webrtc.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Clifix Video Chat</title>
</head>
<body>
<div id="room-controls">
<video id="video" autoplay muted playsinline loop width="100%"></video>
<div class="connect_btn">
<label for="passcode"></label>
<input id="passcode" type="hidden" value="8514"/>
<!--button class="stvbtn" id="start-video" onclick="viplay()">On/Off</button-->
<button class="joinbtn" id="button-join">Join Room</button>
<button class="endbtn" id="button-leave" disabled="disabled">End Call</button>
</div>
</div>
<!-- EDIT_CODE -->
<script src="//media.twiliocdn.com/sdk/js/video/releases/2.3.0/twilio-video.min.js"></script>
<script src="index.js"></script>
</body>
</html>
My nodejs code:
'use strict';
(() => {
//const ROOM_NAME = 'demo';
var urltemp = location.search;
var array = urltemp.split('?');
var array1 = array[1];
var array2 = array1.split('=');
var id = array2[1];
const ROOM_NAME = id;
const Video = Twilio.Video;
let videoRoom, localStream;
const video = document.getElementById('video');
// preview screen
navigator.mediaDevices
.getUserMedia({ video: true, audio: true })
.then((vid) => {
video.srcObject = vid;
localStream = vid;
});
// buttons
const joinRoomButton = document.getElementById('button-join');
const leaveRoomButton = document.getElementById('button-leave');
joinRoomButton.onclick = () => {
//video.play();
// get access token
fetch(`video-token?passcode=${getPasscode()}&room=${ROOM_NAME}`)
.then((resp) => {
if (resp.ok) {
var url=window.location.href,
separator = (url.indexOf("?")===-1)?"?":"&",
newParam=separator + "join=true";
var newUrl=url.replace(newParam,"");
newUrl+=newParam;
window.history.replaceState(null,null,newUrl);
return resp.json();
} else {
console.error(resp);
if (resp.status === 401) {
throw new Error('Go Back & Join Again');
} else {
throw new Error('Unexpected error. Open dev tools for logs');
}
}
})
.then((body) => {
const token = body.token;
//console.log(token);
//connect to room
return Video.connect(token, { name: ROOM_NAME });
})
.then((room) => {
//console.log(`Connected to Room ${room.name}`);
videoRoom = room;
room.participants.forEach(participantConnected);
room.on('participantConnected', participantConnected);
room.on('participantDisconnected', participantDisconnected);
room.once('disconnected', (error) =>
room.participants.forEach(participantDisconnected)
);
joinRoomButton.disabled = true;
leaveRoomButton.disabled = false;
})
.catch((err) => {
alert(err.message);
});
};
// leave room
leaveRoomButton.onclick = () => {
var url=window.location.href,
separator = (url.indexOf("?")===-1)?"?":"&",
newParam=separator + "end=true";
var newUrl=url.replace(newParam,"");
newUrl+=newParam;
window.history.replaceState(null,null,newUrl);
videoRoom.disconnect();
//console.log(`Disconnected from Room ${videoRoom.name}`);
joinRoomButton.disabled = false;
leaveRoomButton.disabled = true;
};
})();
const getPasscode = () => {
const passcodeInput = document.getElementById('passcode') || {};
const passcode = passcodeInput.value;
passcodeInput.value = '';
return passcode;
};
// connect participant
const participantConnected = (participant) => {
//console.log(`Participant ${participant.identity} connected'`);
const div = document.createElement('div'); //create div for new participant
div.id = participant.sid;
participant.on('trackSubscribed', (track) => trackSubscribed(div, track));
participant.on('trackUnsubscribed', trackUnsubscribed);
participant.tracks.forEach((publication) => {
if (publication.isSubscribed) {
trackSubscribed(div, publication.track);
}
});
document.body.appendChild(div);
};
const participantDisconnected = (participant) => {
//console.log(`Participant ${participant.identity} disconnected.`);
document.getElementById(participant.sid).remove();
};
const trackSubscribed = (div, track) => {
div.appendChild(track.attach());
};
const trackUnsubscribed = (track) => {
track.detach().forEach((element) => element.remove());
};
As per my understanding, before this my video was not working on iOS safari then I have done modifications in my HTML video code.
From this:
<video id="video" autoplay muted width="100%"></video>
To:
<video id="video" autoplay muted playsinline loop width="100%"></video>
Then it starts working as having video freezing at the iOS User side when he/she start calling.

Twilio developer evangelist here.
When you call Video.connect the Video SDK will ask for permission to use your microphone and camera. Safari does not like giving access to the microphone and camera more than once at a time and since you also ask for media access to show the preview, it drops the preview tracks and creates new tracks for the video call. This is why the preview goes dark, but other participants can see and hear the video/audio.
Instead, you should reuse the tracks that you got for the preview by storing a reference to them and then passing them to Video.connect as the tracks property in the ConnectOptions. You already store a reference to the localStream so you can use that when you get to connect, like this:
return Video.connect(token, {
name: ROOM_NAME,
tracks: localStream.getTracks()
});
That way the tracks for the preview will be re-used for the video call and nothing should go dark.

Related

Can change video quality settings for some Vimeo videos only in iOS

Some of my Vimeo videos rendered in the iOS web view show the quality settings to toggle between different qualities. But in other videos, I can only see 360p quality. Is there any specific reason for this behavior?
I can toggle between qualities inside the Android Web view.
I'm using a React Native Web View to render the Vimeo player.
My web view template
<html>
<head>
<meta name="viewport" content="width=device-width initial-scale=1.0 maximum-scale=1 user-scalable=0 minimum-scale=1">
</head>
<body style="width: 100%; height: 100%; margin: 0;">
<div style="width: 100%; height: 100%;">
<div id="video" style="width: 100%; height: 100%; display: flex; justify-content: center;">
</div>
</div>
<script id="vimeo" async src="https://player.vimeo.com/api/player.js"></script>
<script>
function webViewBridge() {
const sendEvent = (evt, data = null) => {
// Passes events through the bridge
var payload = {
name: evt,
data: data
};
window.ReactNativeWebView.postMessage(JSON.stringify(payload));
}
var options = { id: '${VIDEO_ID}' }
const player = new Vimeo.Player('video', options)
player.ready().then(function () {
player.on('play', function () {
sendEvent('play');
})
player.on('ended', function () {
sendEvent('finish');
})
player.on('error', function () {
sendEvent('error', "Player error");
})
sendEvent('ready');
}).catch((e) => {
sendEvent('error', e.message);
})
}
let script = document.querySelector('#vimeo');
script.addEventListener('load', function () {
webViewBridge();
});
</script>
</body>
</html>

Printing from a BrowserView in electron 10

In my electron app, a user can select one or more images for printing. To do this, I create a BrowserView which is not visible, load html into it and print it before destroying the view. This worked ok up to Electron 5. But after upgrading my app to electron 10, the printing still occurs but the image is broken (not visible). Any ideas?
Here is a sample of the HTML used to initialize my browser view:
<!DOCTYPE html>
<html>
<head>
<style>#media print { #page { margin: 0; padding: 0;} html, body { margin: 0; padding: 0; height: 100%; width: 100%; } html body *:not(.tempPrinterPaper) {display: none; visibility: hidden; z-index: -5000; } .tempPrinterPaper { display: flex; align-items: center; justify-content: center; position: relative; page-break-after: always; page-break-inside: avoid; overflow: hidden; height: 100%; width: 100%; border: none; margin: 0; padding: 0; background-color: #FFFFFF; text-align: center; align-self: stretch; } .tempPrinterPaper img.tempPrinterPaperImage { display: flex; position: relative; height: auto; max-height: 100%; max-width: 100%; margin: 0; padding: 0; z-index: 500000000000; visibility: visible; } }</style>
</head>
<body>
<div class="tempPrinterPaper"><img class="tempPrinterPaperImage" src="C:\Users\igweo\OneDrive\Pictures\rts9nzl-e1526310385107.jpg" /></div>
</body>
</html>
Here is the code for printing:
// now initialize browser window
printerWindow = new remote.BrowserView( {webPreferences: {webSecurity: false}} );
// load url
printerWindow.webContents.loadURL('data:text/html;charset=utf-8,' + encodeURIComponent(printerHTML));
// after contents have been loaded
printerWindow.webContents.on('did-finish-load', function() {
printerWindow.webContents.print({silent: false, printBackground: false}, function(res) {
// if printing is successful, show a notification
if (res) {
//let printNotification = new Notification('Image' + ((currentPrintList.length > 1) ? 's' : '') + ' successfully sent to printer', {icon: 'static/icons/logoFilledBlue.png'});
let printNotification = new Notification('Image' + ((currentPrintList.length > 1) ? 's' : '') + ' successfully sent to printer', {body: app_name});
}
// clean up print list
//currentPrintList.length = 0;
// after printing is done, destroy browser window
printerWindow.destroy();
// just to be sure :-)
printerWindow = null;
});
});
Unfortunately in electron 10, the old ways no longer seem to work. What I have now done is to create a file called print.html, then write my html contents to the file and print it from the main process.
In app.js
function showPrintDialog() {
// build html string to be printed
let printHTML = '<!DOCTYPE html><html><head><style>#media print { #page { margin: 0; padding: 0;} }</style></head><body>HELLO WORLD</body></html>';
// save file in the userdata directory
let printFilePath = app.getPath('userData') + "\\print.html";
// write to file using powershell (THIS IS ONLY FOR WINDOWS)
let cmd = ['"' + printerHTML + '" | Set-Content -Path "' + printFilePath + '"'];
let cx = cp.spawn('powershell.exe', cmd);
// wait for completion
cx.stdout.on('close', function(data) {
(async function() {
// invoke ipc function to display a dialog box and send the required parameters
let printResult = await ipcRenderer.invoke('show-print-dialog', { printFilePath: printFilePath, successMessage: 'Successfully sent to printer'});
}) ();
});
}
Also, in app.js, we need a function to show notifications when printing is completed:
ipcRenderer.on('show-notification', function(event, args) {
// show a notification
showNotification(args);
});
Now, in our main.js, we will create a browserview with the written file and call the print command. When it is done, request a notification be shown.
// show printing dialog and handle printing
ipcMain.handle('show-print-dialog', async(event, args) => {
// create a browser view
try {
// now initialize browser window
let printerWindow = new BrowserView( {webPreferences: {worldSafeExecuteJavaScript: true, contextIsolation: true}});
// At this point, there should be a file called print.html in the local app path for the user
// This should be to C:\Users\username\AppData\Roaming\Photo Viewer Classic\print.html
printerWindow.webContents.loadURL(args.printFilePath);
// after contents have been loaded
printerWindow.webContents.on('did-finish-load', async function() {
// show print dialog
printerWindow.webContents.print({silent: false, printBackground: false}, function(res) {
// if printing is successful, res will return true
if (res) {
// show notification
event.sender.send('show-notification', args.successMessage);
}
// after printing is done, destroy browser window
printerWindow.destroy();
// just to be sure :-)
printerWindow = null;
});
});
} catch (e) { console.log(e); }
// If failed, simply return false
});

How to take screenshot using electronjs?

I'm building a cross-platform desktop application. I'm using electronjs framework for my desktop app development.And I want to add a functionality of taking screenshot every 5 minutes when my app starts!
help will be appreciated
my main.js
// Modules to control application life and create native browser window
const {app, BrowserWindow,Tray,Menu} = require('electron')
const path = require('path')
const iconz = path.join(__dirname,'/img/download.png')
const fs = require('fs')
var config = require('./login.json');
const shell = require('electron').shell
let tray = null
function createWindow () {
tray = new Tray(iconz)
const contextMenu = Menu.buildFromTemplate([
{ label: 'User:'+ config.username, type: 'radio',enabled:false},
{type:'separator'},
{ label: 'Show DeskTime', type: 'radio',
click() {
shell.openExternal('http://coinmarketcap.com')
}
},
{type:'separator'},
{ label: 'Private Time', type: 'radio',
click() {
checked:true
}
},
{type:'separator'},
{ label: 'LogOut', type: 'radio' },
{type:'separator'},
{ label: 'Quit', type: 'radio',
click() {
app.quit()
}
}
])
tray.setToolTip('This is my application.')
tray.setContextMenu(contextMenu)
console.log(config.username + ' ' + config.password);
if(config.username == ""){
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
}
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
my index.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {font-family: Arial, Helvetica, sans-serif;}
form {border: 3px solid #f1f1f1;}
input[type=text], input[type=password] {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
box-sizing: border-box;
}
button {
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
width: 100%;
}
button:hover {
opacity: 0.8;
}
.cancelbtn {
width: auto;
padding: 10px 18px;
background-color: #f44336;
}
.imgcontainer {
text-align: center;
margin: 12px 0 6px 0;
}
img.avatar {
width: 20%;
border-radius: 40%;
}
.container {
padding: 16px;
}
span.psw {
float: right;
padding-top: 16px;
}
/* Change styles for span and cancel button on extra small screens */
#media screen and (max-width: 300px) {
span.psw {
display: block;
float: none;
}
.cancelbtn {
width: 100%;
}
}
</style>
</head>
<body>
<h2>Login Form</h2>
<form action="/action_page.php" method="post">
<div class="imgcontainer">
<img src="login_logo.png" alt="Avatar" class="avatar">
</div>
<div class="container">
<label for="uname"><b>Username</b></label>
<input type="text" placeholder="Enter Username" name="uname" required>
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="psw" required>
<button type="submit">Login</button>
<label>
<input type="checkbox" checked="checked" name="remember"> Remember me
</label>
</div>
<div class="container" style="background-color:#f1f1f1">
<span class="psw">Forgot password?</span>
</div>
</form>
<label id="screenshot-path">Path:</label>
<button id="screen-shot" type="button" class="cancelbtn">Singup</button>
</body>
<script src="./renderer.js"></script>
</html>
My codes are given above, please go through this and help me to take screenshot on a certain interval.And also how to save in screen shots in predefined folder.
You can use contents.capturePage([rect]) on your main process. if you omits rect args it will capture the whole window. This will return a promise with native image .
To capture it on every 5 minute, you can set a setInterval(<function>,<time in millis>)
To save on specific folder you can use path module
ex:
const path = require('path')
const myFolderPath = path.join(__dirname, "myfolderinsideProject")
fs.writeFile(path.join(myFolderPath,`test${count}.png`), ....)
example code to save Captured window on current project folder:
// Modules to control application life and create native browser window
const {app, BrowserWindow } = require('electron')
const path = require('path')
const fs = require('fs')
let mainWindow, count=0;
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
//starting when the app is ready
app.on('ready', () => {
//setting the time interval for 3 second (3000 in millis)
setInterval(()=>{
console.log(`Capturing Count: ${count}`)
//start capturing the window
mainWindow.webContents.capturePage().then(image =>
{
//writing image to the disk
fs.writeFile(`test${count}.png`, image.toPNG(), (err) => {
if (err) throw err
console.log('Image Saved')
count++
})
})
}, 3000); //tome in millis
});
or you can use this npm package on renderer process

How to check if a selected string contains a substring of an highlight in epubjs

As the title above.
Assume, I have a paragraph:
It will be seen that this mere painstaking burrower and grub-worm of a poor devil of a Sub-Sub appears to have gone through the long Vaticans and street-stalls of the earth..
The bold string is a highlight. When I drag my mouse to select string
grub-worm of a poor devil of a Sub-Sub
Then I want to check if my selected text contains the highlight(or the part of the highlight) or not. How could I do that?
The code below is the example to add a highlight when I select a text.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>EPUB.js Highlights Example</title>
<script src="../dist/epub.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
<link rel="stylesheet" type="text/css" href="examples.css">
<style type="text/css">
::selection {
background: yellow;
}
#extras {
width: 600px;
margin: 40px auto;
}
#highlights {
list-style: none;
margin-left: 0;
padding: 0;
}
#highlights li {
list-style: none;
margin-bottom: 20px;
border-top: 1px solid #E2E2E2;
padding: 10px;
}
#highlights a {
display: block;
}
#viewer.spreads {
top: 0;
margin-top: 50px;
}
[ref="epubjs-mk"] {
background: url("data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZycgeG1sbnM6eGxpbms9J2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsnIHg9JzBweCcgeT0nMHB4JyB2aWV3Qm94PScwIDAgNzUgNzUnPjxnIGZpbGw9JyNCREJEQkQnIGlkPSdidWJibGUnPjxwYXRoIGNsYXNzPSdzdDAnIGQ9J00zNy41LDkuNEMxOS42LDkuNCw1LDIwLjUsNSwzNC4zYzAsNS45LDIuNywxMS4zLDcuMSwxNS42TDkuNiw2NS42bDE5LTcuM2MyLjgsMC42LDUuOCwwLjksOC45LDAuOSBDNTUuNSw1OS4yLDcwLDQ4LjEsNzAsMzQuM0M3MCwyMC41LDU1LjQsOS40LDM3LjUsOS40eicvPjwvZz48L3N2Zz4=") no-repeat;
width: 20px;
height: 20px;
cursor: pointer;
margin-left: 0;
}
</style>
</head>
<body>
<div id="frame">
<div id="viewer" class="spreads"></div>
<a id="prev" href="#prev" class="arrow">‹</a>
<a id="next" href="#next" class="arrow">›</a>
</div>
<div id="extras">
<ul id="highlights"></ul>
</div>
<script>
// Load the opf
var book = ePub("https://s3.amazonaws.com/moby-dick/OPS/package.opf");
var rendition = book.renderTo("viewer", {
width: "100%",
height: 600,
ignoreClass: 'annotator-hl',
manager: "continuous"
});
var displayed = rendition.display(6);
// Navigation loaded
book.loaded.navigation.then(function(toc){
// console.log(toc);
});
var next = document.getElementById("next");
next.addEventListener("click", function(){
rendition.next();
}, false);
var prev = document.getElementById("prev");
prev.addEventListener("click", function(){
rendition.prev();
}, false);
var keyListener = function(e){
// Left Key
if ((e.keyCode || e.which) == 37) {
rendition.prev();
}
// Right Key
if ((e.keyCode || e.which) == 39) {
rendition.next();
}
};
rendition.on("keyup", keyListener);
document.addEventListener("keyup", keyListener, false);
rendition.on("relocated", function(location){
// console.log(location);
});
// Apply a class to selected text
rendition.on("selected", function(cfiRange, contents) {
rendition.annotations.highlight(cfiRange, {}, (e) => {
console.log("highlight clicked", e.target);
});
contents.window.getSelection().removeAllRanges();
});
this.rendition.themes.default({
'::selection': {
'background': 'rgba(255,255,0, 0.3)'
},
'.epubjs-hl' : {
'fill': 'yellow', 'fill-opacity': '0.3', 'mix-blend-mode': 'multiply'
}
});
// Illustration of how to get text from a saved cfiRange
var highlights = document.getElementById('highlights');
rendition.on("selected", function(cfiRange) {
book.getRange(cfiRange).then(function (range) {
var text;
var li = document.createElement('li');
var a = document.createElement('a');
var remove = document.createElement('a');
var textNode;
if (range) {
text = range.toString();
textNode = document.createTextNode(text);
a.textContent = cfiRange;
a.href = "#" + cfiRange;
a.onclick = function () {
rendition.display(cfiRange);
};
remove.textContent = "remove";
remove.href = "#" + cfiRange;
remove.onclick = function () {
rendition.annotations.remove(cfiRange);
return false;
};
li.appendChild(a);
li.appendChild(textNode);
li.appendChild(remove);
highlights.appendChild(li);
}
})
});
</script>
</body>
</html>
I assume you only know the functionality of epubjs you listed above. From rendition.on(selected,...), we can get output: cfiRange. From book.getRange(cfiRange).then(function (range)..., we can get output: range.
That means whenever we select a word or sentence, we get cfiRange and range.
cfiRange is epubcfi(/6/10[id139]!/4/2[filepos12266]/6,/3:1,/3:4, which based on position of the selected word. I don't know how it calculates/works but if you do then you can check if the cfiRange contains a existing highlight word's cfiRange.
range.toString() can give you the text. if your application is only storing a word. then you can check if the new selected word == or contain your existing highlight word.

dynamic legend for fusion table map

I have a modified sample of fusion table map and its code is given below.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="UTF-8">
<title>Fusion Tables Layer Example: Dynamic styles and templates</title>
<style>
body { font-family: Arial, sans-serif; font-size: 12px; }
#map-canvas { height: 660px; width: 100%; }
#map-canvas img { max-width: none; }
#visualization { height: 100%; width: 100%; }
#legend1 { width: 200px; background: #FFF;padding: 10px; margin: 5px;font-size: 12px;font-family: Arial, sans-serif;border: 1px solid black;}
.color {border: 1px solid;height: 12px;width: 15px; margin-right: 3px;float: left;}
.red {background: #C00;}
.blue {background: #06C;}
</style>
<script type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
function initialize() {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(37.4, -122.1),
zoom: 10,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var layer = new google.maps.FusionTablesLayer({
query: {
select: 'Address',
from: '15UY2pgiz8sRkq37p2TaJd64U7M_2HDVqHT3Quw'
},
map: map,
styleId: 1,
templateId: 1
});
var legend1 = document.createElement('div');
legend1.id = 'legend1';
var content1 = [];
content1.push('<p><div class="color red"></div>Red markers</p>');
legend1.innerHTML = content1.join('');
legend1.index = 1;
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(legend1);
var legend2 = document.createElement('div');
legend2.id = 'legend1';
var content2 = [];
content2.push('<p><div class="color blue"></div>Blue markers</p>');
legend2.innerHTML = content2.join('');
legend2.index = 1;
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(legend2);
google.maps.event.addDomListener(document.getElementById('style'),
'change', function() {
var selectedStyle = this.value;
layer.set('styleId', selectedStyle);
var selectedTemplate = this.value;
layer.set('templateId', selectedTemplate);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<div id="map-canvas"></div>
<div>
<label>Select style:</label>
<select id="style">
<option value="1">Red</option>
<option value="2">Blue</option>
</select>
</div>
</body>
</html>
How can I add dynamic legend to this map so that when selecting blue markers, the legend should show only a blue marker with its name and when selecting red markers it will show the red marker icon in legend.
You must clear the controls(remove all legends) and then add the desired legend again.
right before
google.maps.event.addDomListener(document.getElementById('style')[...]
add this code:
//we need a copy of all legends(nodes),
//otherwise they wouldn't be accessible when they have been removed
var clonedArray = map.controls[google.maps.ControlPosition.RIGHT_BOTTOM]
.getArray().slice();
//observe changes of the styleId
google.maps.event.addListener(layer,'styleid_changed',function(){
//clear the controls
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].clear();
//add the desired control
map.controls[google.maps.ControlPosition.RIGHT_BOTTOM]
.push(clonedArray[this.get('styleId')-1])
});
//trigger the event to initially have only the legend
//based on the selected style
google.maps.event.trigger(layer,'styleid_changed');
Demo: http://jsfiddle.net/doktormolle/t3nY6/

Resources