d3 svg transition has slight unwanted horizontal movement on Firefox - html

The following has some SVG squares that march upwards once per second. In Google Chrome it looks fine. In Firefox, the squares shift right and left by about 1 pixel which is not what I intended.
Can anyone help figure out why?
I'm sorry this code snippet is not simpler; this is about as basic as I could go from a much longer file in which I removed all the unrelated aspects.
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
<style type='text/css'>
.hidden {
display: none;
}
#ticktock {
position: absolute;
top: 550px;
left: 400px;
}
svg rect.cell {
fill: none;
stroke: steelblue;
}
</style>
<script type='text/javascript'>
document.addEventListener('DOMContentLoaded',function(event) {
var L = 25;
var maxFacetCount = 8;
var state = {
nexttick: 0,
ticksize: 500,
n: -8,
nx: 8,
wheel: [],
nfacet: maxFacetCount,
init: true,
ticktock: true
};
function update_state(state)
{
if (state.ticktock)
{
if (state.wheel.length >= state.nfacet)
state.wheel.shift();
state.wheel.push({n: ++state.n });
}
}
state.wheel = state.wheel.slice(-1);
function prepare_view(state)
{
var width = 60 + (state.nx+0.5)*(L+2);
var height = 5 + (state.nfacet+0.5)*L;
var svg = d3.select("#wheel-container").append("svg")
.attr("width", width)
.attr("height", height);
var x1 = L*0.5+5;
var wheel = svg.append('g')
.attr('id','wheel')
.attr('transform','translate('+x1+',0)');
}
prepare_view(state);
function facet_enter(facets, t)
{
var facet = facets.append('g');
for (var i = 0; i < state.nx; ++i)
{
facet.append('rect')
.attr('x',i*L)
.attr('y',0)
.attr('width',L)
.attr('height',L)
.attr('class','cell');
}
facet_move(facet, state.init ? null : t);
}
function facet_move(facet, t)
{
(t ? facet.transition(t) : facet)
.attr('opacity',function(d,i) {
var age = state.n - d.n;
return age == 0 ? 0 : 1-age/state.nfacet; })
.attr('transform',function(d,i) { return 'translate(0,'+((d.n-state.n+state.nfacet-1)*L)+')'; });
}
function facet_update(facets, t)
{
facet_move(facets, t);
}
function update_view(state, ticktock)
{
var wheel = d3.select("#wheel");
var facets = wheel.selectAll('g');
if (state.ticktock)
{
var t = d3.transition().duration(300);
var upd = facets
.data(state.wheel, function(d,i) { return d.n; });
upd .call(facet_update, t)
.enter()
.call(facet_enter, t)
upd.exit()
.transition(t)
.attr('transform','translate (0,'+(-L)+')')
.remove();
}
else
{
// tock
var t = d3.transition().duration(100);
var t2 = t.transition().duration(100);
var upd = facets
.data(state.wheel, function(d,i) { return d.n; });
upd.call(facet_update, t)
.enter()
.call(facet_enter, t);
}
}
var tmr = d3.timer(function(elapsed) {
var do_something = false;
while (elapsed >= state.nexttick)
{
do_something = true;
state.nexttick += state.ticksize;
}
if (do_something && !(d3.select('#pause').property('checked') ))
{
state.ticktock = !state.ticktock;
update_state(state);
update_view(state);
state.init = false;
}
} );
});
</script>
</head>
<body>
<div id='wheel-container' ></div>
<form class="">
<input type="checkbox" id="pause" name="pause">pause</input>
</form>
<div id='ticktock' class='hidden'></div>
</body>
</html>

Looks like floating-point rounding errors strike again. I changed to shape-rendering: crispEdges; and then rounded to an integer translate in one of the root elements and that seems to fix most of it (still a little residual y-axis shift).
was:
var x1 = L*0.5+5;
var wheel = svg.append('g')
.attr('id','wheel')
.attr('transform','translate('+x1+',0)');
changed to:
var x1 = Math.round(L*0.5+5);
var wheel = svg.append('g')
.attr('id','wheel')
.attr('transform','translate('+x1+',0)');
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
<style type='text/css'>
.hidden {
display: none;
}
#ticktock {
position: absolute;
top: 550px;
left: 400px;
}
svg rect.cell {
fill: none;
stroke: steelblue;
shape-rendering: crispEdges;
}
</style>
<script type='text/javascript'>
document.addEventListener('DOMContentLoaded',function(event) {
var L = 25;
var maxFacetCount = 8;
var state = {
nexttick: 0,
ticksize: 500,
n: -8,
nx: 8,
wheel: [],
nfacet: maxFacetCount,
init: true,
ticktock: true
};
function update_state(state)
{
if (state.ticktock)
{
if (state.wheel.length >= state.nfacet)
state.wheel.shift();
state.wheel.push({n: ++state.n });
}
}
state.wheel = state.wheel.slice(-1);
function prepare_view(state)
{
var width = 60 + (state.nx+0.5)*(L+2);
var height = 5 + (state.nfacet+0.5)*L;
var svg = d3.select("#wheel-container").append("svg")
.attr("width", width)
.attr("height", height);
var x1 = Math.round(L*0.5+5);
var wheel = svg.append('g')
.attr('id','wheel')
.attr('transform','translate('+x1+',0)');
}
prepare_view(state);
function facet_enter(facets, t)
{
var facet = facets.append('g');
for (var i = 0; i < state.nx; ++i)
{
facet.append('rect')
.attr('x',i*L)
.attr('y',0)
.attr('width',L)
.attr('height',L)
.attr('class','cell');
}
facet_move(facet, state.init ? null : t);
}
function facet_move(facet, t)
{
(t ? facet.transition(t) : facet)
.attr('opacity',function(d,i) {
var age = state.n - d.n;
return age == 0 ? 0 : 1-age/state.nfacet; })
.attr('transform',function(d,i) { return 'translate(0,'+((d.n-state.n+state.nfacet-1)*L)+')'; });
}
function facet_update(facets, t)
{
facet_move(facets, t);
}
function update_view(state, ticktock)
{
var wheel = d3.select("#wheel");
var facets = wheel.selectAll('g');
if (state.ticktock)
{
var t = d3.transition().duration(300);
var upd = facets
.data(state.wheel, function(d,i) { return d.n; });
upd .call(facet_update, t)
.enter()
.call(facet_enter, t)
upd.exit()
.transition(t)
.attr('transform','translate (0,'+(-L)+')')
.remove();
}
else
{
// tock
var t = d3.transition().duration(100);
var t2 = t.transition().duration(100);
var upd = facets
.data(state.wheel, function(d,i) { return d.n; });
upd.call(facet_update, t)
.enter()
.call(facet_enter, t);
}
}
var tmr = d3.timer(function(elapsed) {
var do_something = false;
while (elapsed >= state.nexttick)
{
do_something = true;
state.nexttick += state.ticksize;
}
if (do_something && !(d3.select('#pause').property('checked') ))
{
state.ticktock = !state.ticktock;
update_state(state);
update_view(state);
state.init = false;
}
} );
});
</script>
</head>
<body>
<div id='wheel-container' ></div>
<form class="">
<input type="checkbox" id="pause" name="pause">pause</input>
</form>
<div id='ticktock' class='hidden'></div>
</body>
</html>

Related

Getting NaN when a directive is used in angularJs

I am using a directive to show the number count effect for my dashboard when i used the directive for the h3 i am getting the result as NaN. when i remove the directive from the h3 i am getting the correct output.
When i looked into the directive i can the the value is get from element which shows the value as NaN. can anyone tell me what is wrong in the code?
Output with directive:
<h3 animate-numbers="" class="ng-binding">NaN</h3>
Html:
<h3 animate-numbers>{{vm.dashboard.no_of_applications}}</h3>
Controller:
vm.dashboard = {
no_of_users: 0,
no_of_applications: 0,
no_of_departments: 0,
no_of_schemes: 0,
};
Directive:
'use strict';
angular.module('ss')
.directive('animateNumbers', function ($timeout, $log) {
return {
replace: false,
scope: true,
link: function (scope, element) {
var e = element[0];
$log.log('e is', e);
var refreshInterval = 30;
var duration = 1000; //milliseconds
var number = parseInt(e.innerText);
var step = 0;
var num = 0;
var steps = Math.ceil(duration / refreshInterval);
var increment = (number / steps);
var percentCompleted = 0;
var lastNumberSlowCount = 3;
if (number > lastNumberSlowCount) {
number = number - lastNumberSlowCount;
}
scope.timoutId = null;
var slowCounter = function () {
scope.timoutId = $timeout(function () {
lastNumberSlowCount --;
if (lastNumberSlowCount < 0) {
$timeout.cancel(scope.timoutId);
} else {
number++;
e.textContent = number;
slowCounter();
}
}, 500);
};
var counter = function () {
scope.timoutId = $timeout(function () {
num += increment;
percentCompleted = Math.round((num / number) * 100);
if (percentCompleted > 60 && percentCompleted < 80) {
refreshInterval = refreshInterval + 10;
} else if (percentCompleted > 90) {
refreshInterval = 200;
}
step++;
if (step >= steps) {
$timeout.cancel(scope.timoutId);
num = number;
e.textContent = number;
if (number > lastNumberSlowCount) {
slowCounter();
}
} else {
e.textContent = Math.round(num);
counter();
}
}, refreshInterval);
};
counter();
return true;
}
};
});

Not able to get ng-bind-html to work

Problem: I am trying to use ng-bind-html but I am getting the following errors on the console:
The following is the controller where I am calling ngSanitize:
and using the following file:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-sanitize.js"></script>
In my form, I do the following to use ng-bind-html. So when I try to see my results, it is still rendering the &rather then &:
<div ng-bind-html="e.Specialty"></div>
and the following is what occurs in the Specialty:
Any help would be appreciated.
#lealceldeiro: Here is the controller in which I am trying to implement your suggestion but not sure where I will add it:
(
function(){
var $scope, $location;
var indexApp = angular.module('indexApp',['ui.bootstrap', 'ngSanitize']);
indexApp.controller('IndexController',function($scope,$sce,$http,$location,anchorSmoothScroll){
$scope.Lang = 'initVal';
$scope.ShowResults = false;
$scope.ShowDesc = true;
$scope.NoResults = false;
$scope.currentPage = 1;
$scope.maxPageNumbersToShow = 10;
$scope.formModel = {};
$scope.searchMode = 0;
$scope.miles = [{'value':'5'},{'value':'10'},{'value':'15'},{'value':'20' }];
$scope.Specialties = [{'value':'Family practice'},{'value':'General practice'},{'value':'Internal medicine'},{'value':'Pediatrics'}];
$scope.Gender = [{'value':'Male'},{'value':'Female'}];
$scope.Languages = {};
$scope.Cities = {};
//$scope.lastAction = '';
$scope.searchParam = {};
$("input").removeAttr('disabled');
$scope.searchParam.Distance = $scope.miles[0];
$scope.GetCurrentZip = function (){
try{
var lon, lat;
// console.log('starting geoposition code.');
if("geolocation" in navigator){
window.navigator.geolocation.getCurrentPosition(function(pos){
lat = pos.coords.latitude.toFixed(3);
lon = pos.coords.longitude.toFixed(3);
// console.log(lat + ' ' + lon);
$http.get("/Brokers-en-us/includes/remote/ReturnCurrentZipcode.cfm?Lat=" + lat + "&Lon=" + lon)
.then(function(response){
$scope.searchParam.Zip = response.data;
})
})
}
else{ console.log('No geolocation'); }
}
catch(err) { console.log(err.message); }
}
$scope.GetCityList = function (){
try{
$http.get("/Brokers-en-us/includes/remote/ReturnCityList.cfm")
.then(function(response){
$scope.Cities = response.data.Cities;
})
}
catch(err){}
}
$scope.GetLangList = function (){
try{
$http.get("/Brokers-en-us/includes/remote/ReturnLangList.cfm")
.then(function(response){
$scope.Languages = response.data.Languages;
})
}
catch(err){}
}
$scope.SearchProvider = function(searchParam){
try{
//debugger;
$scope.searchMode = 1;
var queryString='';
if($scope.formModel && $scope.formModel !== searchParam){
$scope.resultsCount = 0;
currentPage = 1;
}
if(searchParam){
//debugger;
$scope.formModel = searchParam;
for(var param in searchParam){
if(searchParam.hasOwnProperty(param)){
var paramValue = searchParam[param].value ? searchParam[param].value : searchParam[param];
if (paramValue.length > 0)
queryString += param + '=' + paramValue + '&';
}
}
}
console.log(queryString);
queryString= '?' + queryString + 'currentpage=' + $scope.currentPage;
$http.get("/Brokers-en-us/includes/remote/ReturnProvidersList.cfm" + queryString)
.then(function(response){
$scope.providers = response.data.provider;
$scope.resultsCount = response.data.rowCount;
if (!$scope.providers){
$scope.NoResults = true;
$scope.ShowResults = false;
$scope.ShowDesc = false;
}
else{
$scope.NoResults = false;
$scope.ShowResults = true;
$scope.ShowDesc = false;
}
})
}
catch(err){ alert('No response.: ' + err.message); }
}
/*Testing purposes*/
$scope.clearTopForm = function(searchParam){
//console.log("I clicked this.")
}
/*Clears the drop downs and input fields*/
$scope.$watch('searchParam.Distance', function(newValue, oldValue) {
//debugger;
if(newValue != ''){
//$scope.lastAction = 'miles';
$scope.searchParam.City = '';
$scope.searchParam.Specialty = '';
$scope.searchParam.Gender = '';
}
});
$scope.$watch('searchParam.Zip', function(newValue, oldValue) {
if(newValue != ''){
//$scope.lastAction = 'miles';
$scope.searchParam.Gender = '';
$scope.searchParam.Specialty = '';
$scope.searchParam.City = '';
}
});
$scope.cityChange = function(){
//debugger;
if($scope.searchParam.City != ''){
//$scope.lastAction = 'city';
$scope.searchParam.Distance = '';
$scope.searchParam.Zip = '';
}
}
$scope.specialtyChange = function(){
//debugger;
if($scope.searchParam.Specialty != ''){
//$scope.lastAction = 'specialty';
$scope.searchParam.Distance = '';
$scope.searchParam.Zip = '';
}
}
$scope.genderChange = function(){
//debugger;
if($scope.searchParam.Gender != ''){
//$scope.lastAction = 'gender';
$scope.searchParam.Distance = '';
$scope.searchParam.Zip = '';
}
}
$scope.$watchGroup(['currentPage'], function(){
try{
if($scope.searchMode == 1){
$scope.SearchProvider($scope.formModel);
}
}
catch(err){}
});
$scope.GetCityList();
$scope.GetLangList();
$scope.GetCurrentZip();
$scope.gotoElement = function (eID){
//http://jsfiddle.net/brettdewoody/y65G5/
// set the location.hash to the id of
// the element you wish to scroll to.
//$location.hash('bottom');
// call $anchorScroll()
var browserWidth = screen.availWidth;
if (browserWidth < 768)
anchorSmoothScroll.scrollTo(eID);
};
});
indexApp.service('anchorSmoothScroll', function(){
this.scrollTo = function(eID) {
// This scrolling function
// is from http://www.itnewb.com/tutorial/Creating-the-Smooth-Scroll-Effect-with-JavaScript
var startY = currentYPosition();
var stopY = elmYPosition(eID);
var distance = stopY > startY ? stopY - startY : startY - stopY;
if (distance < 100) {
scrollTo(0, stopY); return;
}
var speed = Math.round(distance / 100);
if (speed >= 20) speed = 20;
var step = Math.round(distance / 25);
var leapY = stopY > startY ? startY + step : startY - step;
var timer = 0;
if (stopY > startY) {
for ( var i=startY; i<stopY; i+=step ) {
setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
leapY += step; if (leapY > stopY) leapY = stopY; timer++;
} return;
}
for ( var i=startY; i>stopY; i-=step ) {
setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);
leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
}
function currentYPosition() {
// Firefox, Chrome, Opera, Safari
if (self.pageYOffset) return self.pageYOffset;
// Internet Explorer 6 - standards mode
if (document.documentElement && document.documentElement.scrollTop)
return document.documentElement.scrollTop;
// Internet Explorer 6, 7 and 8
if (document.body.scrollTop) return document.body.scrollTop;
return 0;
}
function elmYPosition(eID) {
var elm = document.getElementById(eID);
var y = elm.offsetTop;
var node = elm;
while (node.offsetParent && node.offsetParent != document.body) {
node = node.offsetParent;
y += node.offsetTop;
} return y;
}
};
});
indexApp.directive('allowPattern',[allowPatternDirective]);
indexApp.directive('popPopup',[describePopup]);
indexApp.directive('pop', function pop ($tooltip, $timeout) {
var tooltip = $tooltip('pop', 'pop', 'event');
var compile = angular.copy(tooltip.compile);
tooltip.compile = function (element, attrs) {
var first = true;
attrs.$observe('popShow', function (val) {
if (JSON.parse(!first || val || false)) {
$timeout(function(){
element.triggerHandler('event');
});
}
first = false;
});
return compile(element, attrs);
};
return tooltip;
});
indexApp.filter('PhoneNumber', function(){
return function(phoneNumber){
var dash = '-';
var openParen = '(';
var closeParen = ') ';
if(phoneNumber){
var pn = phoneNumber;
pn = [pn.slice(0, 6), dash, pn.slice(6)].join('');
pn = openParen + [pn.slice(0, 3), closeParen, pn.slice(3)].join('');
return pn;
}
return phoneNumber;
}
});
indexApp.filter('Zip', function(){
return function(zipcode){
var dash = '-';
if(zipcode && zipcode.length > 5){
var zc = zipcode;
zc = [zc.slice(0, 5), dash, zc.slice(5)].join('');
return zc;
}
return zipcode;
}
});
function allowPatternDirective(){
return{
restrict: "A",
compile: function(tElement, tAttrs){
return function(scope, element, attrs){
element.bind("keypress", function(event){
var keyCode = event.which || event.keyCode;
var keyCodeChar = String.fromCharCode(keyCode);
if(!keyCodeChar.match(new RegExp(attrs.allowPattern, "i"))){
event.preventDefault();
return false;
}
});
}
}
}
}
function describePopup(){
return {
restrict: 'EA',
replace: true,
scope: { title: '#', content: '#', placement: '#', animation: '&', isOpen: '&' },
templateUrl: 'template/popover/popover.html'
};
}
})();
(function($) {
// #todo Document this.
$.extend($,{ placeholder: {
browser_supported: function() {
return this._supported !== undefined ?
this._supported :
( this._supported = !!('placeholder' in $('<input type="text">')[0]) );
},
shim: function(opts) {
var config = {
color: '#888',
cls: 'placeholder',
selector: 'input[placeholder], textarea[placeholder]'
};
$.extend(config,opts);
return !this.browser_supported() && $(config.selector)._placeholder_shim(config);
}
}});
$.extend($.fn,{
_placeholder_shim: function(config) {
function calcPositionCss(target)
{
var op = $(target).offsetParent().offset();
var ot = $(target).offset();
return {
top: ot.top - op.top,
left: ot.left - op.left,
width: $(target).width()
};
}
function adjustToResizing(label) {
var $target = label.data('target');
if(typeof $target !== "undefined") {
label.css(calcPositionCss($target));
$(window).one("resize", function () { adjustToResizing(label); });
}
}
return this.each(function() {
var $this = $(this);
if( $this.is(':visible') ) {
if( $this.data('placeholder') ) {
var $ol = $this.data('placeholder');
$ol.css(calcPositionCss($this));
return true;
}
var possible_line_height = {};
if( !$this.is('textarea') && $this.css('height') != 'auto') {
possible_line_height = { lineHeight: $this.css('height'), whiteSpace: 'nowrap' };
}
var isBorderBox = ($this.css('box-sizing') === 'border-box');
var isTextarea = $this.is('textarea');
var ol = $('<label />')
.text($this.attr('placeholder'))
.addClass(config.cls)
.css($.extend({
position:'absolute',
display: 'inline',
'float':'none',
overflow:'hidden',
textAlign: 'left',
color: config.color,
cursor: 'text',
paddingTop: !isTextarea && isBorderBox ? '0' : $this.css('padding-top'),
paddingRight: $this.css('padding-right'),
paddingBottom: !isTextarea && isBorderBox ? '0' : $this.css('padding-bottom'),
paddingLeft: $this.css('padding-left'),
fontSize: $this.css('font-size'),
fontFamily: $this.css('font-family'),
fontStyle: $this.css('font-style'),
fontWeight: $this.css('font-weight'),
textTransform: $this.css('text-transform'),
backgroundColor: 'transparent',
zIndex: 99,
}, possible_line_height))
.css(calcPositionCss(this))
.attr('for', this.id)
.data('target',$this)
.click(function(){
if (!$(this).data('target').is(':disabled')) {
$(this).data('target').focus();
}
})
.insertBefore(this);
$this
.data('placeholder', ol)
.on('keydown', function () {
ol.hide();
})
.on('blur change', function () {
ol[$this.val().length ? 'hide' : 'show']();
})
.triggerHandler('blur');
$(window).one("resize", function () { adjustToResizing(ol); });
}
});
}
});
})(jQuery);
jQuery(document).add(window).bind('ready load', function() {
if (jQuery.placeholder) {
jQuery.placeholder.shim();
}
});
When you use ng-bind-html, AngularJS sometimes consider some contents as unsafe (as your case), so you need to use the $sce service in order to "mark" this content as safe (to be used) like this:
$sce.trustAsHtml("CLINICAL & SOCIAL"); (See demo below)
From $sanitize
The input is sanitized by parsing the HTML into tokens. All safe
tokens (from a whitelist) are then serialized back to properly escaped
html string. This means that no unsafe input can make it into the
returned string.
In this case the "unsafe" part is &
angular
.module('app', [])
.controller('ctrl', ctrl);
function ctrl($scope, $sce) {
$scope.Specialty = $sce.trustAsHtml("CLINICAL & SOCIAL");
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular-sanitize.js"></script>
<div ng-app="app" ng-controller="ctrl">
Specialty: <span ng-bind-html="Specialty"></span>
</div>

How to solve the clustering bug in Cesium?

I have found a bug in 1.28:
I produced it by creating lots of entities with label. Howeveer, when I set the clustering enabled, some labels were invisible in 2D.
The screenshot of bug
the code as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description"
content="Use Viewer to start building new applications or easily embed Cesium into existing applications.">
<meta name="cesium-sandcastle-labels" content="Beginner, Showcases">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.20/require.js"></script>
<style>
#convert {
z-index: 100;
top: 30px;
position: absolute;
}
</style>
<script type="text/javascript">
require.config({
baseUrl: '../../../Source',
waitSeconds: 60
});
</script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
#import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar"></div>
<div>
<button id="convert">2/3D转换</button>
</div>
<script id="cesium_sandcastle_script">
var viewer;
function startup(Cesium) {
'use strict';
//Sandcastle_Begin
viewer = new Cesium.Viewer('cesiumContainer');
document.getElementById("convert").onclick = function () {
if (viewer.scene.mode == Cesium.SceneMode.SCENE3D) {
viewer.scene.mode = Cesium.SceneMode.SCENE2D
} else {
viewer.scene.mode = Cesium.SceneMode.SCENE3D
}
};
var modelLayer = new Cesium.CustomDataSource();
for (var i = 0; i < 50; i++) {
var lon = Math.random() * 1000;
var lat = Math.random() * 500;
modelLayer.entities.add({
position: Cesium.Cartesian3.fromDegrees(-75.1641667 + lon, -39.9522222 + lat),
label: {
text: '东海舰队超级无敌',
font: '13px Verdana',
position: Cesium.Cartesian3.fromDegrees(-75.1641667 + lon, -39.9522222 + lat, 100000),
verticalOrigin: Cesium.VerticalOrigin.TOP,
eyeOffset: Cesium.Cartesian3(0, 0, -10000)
},
model: {
position: Cesium.Cartesian3.fromDegrees(-75.1641667 + lon, -39.9522222 + lat, 0),
uri: '../../SampleData/models/CesiumAir/Cesium_Air.glb',
minimumPixelSize: 128,
maximumScale: 20000
}
});
}
var pixelRange = 15;
var minimumClusterSize = 3;
var enabled = true;
modelLayer.clustering.enabled = enabled;
modelLayer.clustering.pixelRange = pixelRange;
modelLayer.clustering.minimumClusterSize = minimumClusterSize;
var removeListener;
var pinBuilder = new Cesium.PinBuilder();
var pin50 = pinBuilder.fromText('50+', Cesium.Color.RED, 48).toDataURL();
var pin40 = pinBuilder.fromText('40+', Cesium.Color.ORANGE, 48).toDataURL();
var pin30 = pinBuilder.fromText('30+', Cesium.Color.YELLOW, 48).toDataURL();
var pin20 = pinBuilder.fromText('20+', Cesium.Color.GREEN, 48).toDataURL();
var pin10 = pinBuilder.fromText('10+', Cesium.Color.BLUE, 48).toDataURL();
var singleDigitPins = new Array(8);
for (var i = 0; i < singleDigitPins.length; ++i) {
singleDigitPins[i] = pinBuilder.fromText('' + (i + 2), Cesium.Color.VIOLET, 48).toDataURL();
}
customStyle();
function customStyle() {
if (Cesium.defined(removeListener)) {
removeListener();
removeListener = undefined;
} else {
removeListener = modelLayer.clustering.clusterEvent.addEventListener(function (clusteredEntities, cluster) {
cluster.label.show = true;
cluster.billboard.show = true;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
if (clusteredEntities.length >= 50) {
cluster.billboard.image = pin50;
} else if (clusteredEntities.length >= 40) {
cluster.billboard.image = pin40;
} else if (clusteredEntities.length >= 30) {
cluster.billboard.image = pin30;
} else if (clusteredEntities.length >= 20) {
cluster.billboard.image = pin20;
} else if (clusteredEntities.length >= 10) {
cluster.billboard.image = pin10;
} else {
cluster.billboard.image = singleDigitPins[clusteredEntities.length - 2];
}
});
}
// force a re-cluster with the new styling
var pixelRange = modelLayer.clustering.pixelRange;
modelLayer.clustering.pixelRange = 0;
modelLayer.clustering.pixelRange = pixelRange;
}
viewer.dataSources.add(modelLayer);
//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
startup(Cesium);
} else if (typeof require === "function") {
require(["Cesium"], startup);
}
</script>
</body>
</html>
This used to work in Cesium v1.26. I have just encountered this same issue with the current Cesium v1.34 and have logged a bug. The labels will appear if you disable clustering.

jquery webcam not working in chrome 35

I am trying to access webcam from jquery webcam API. The sample given below works fine in IE9, Firefox, but unfortunately does not work in Chrome v35. It shows the webcam activated but when I click the "Take Picture" button, it gives me a javascript error saying that webcam.capture is undefined. In the code below, the webcam object does not have any function called capture() in chrome; but its found for Firefox and IE9.
Please help me out!!
Index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="jquery-1.11.0.js"></script>
<script type="text/javascript" src="jquery.webcam.min.js"></script>
</head>
<body>
<p id="status" style="height:22px; color:#c00;font-weight:bold;"></p>
<div id="webcam" style="width:350px;float: left;"">
Take a picture instantly
</div>
<p style="width:350px; float: left;"><canvas id="canvas" height="240" width="320" style="float: left;""></canvas></p>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
main.js
var pos = 0;
var ctx = null;
var cam = null;
var image = null;
var filter_on = false;
var filter_id = 0;
function changeFilter() {
if (filter_on) {
filter_id = (filter_id + 1) & 7;
}
}
function toggleFilter(obj) {
if (filter_on =!filter_on) {
obj.parentNode.style.borderColor = "#c00";
} else {
obj.parentNode.style.borderColor = "#333";
}
}
jQuery("#webcam").webcam({
width: 320,
height: 240,
mode: "callback",
swffile: "http://www.xarg.org/download/jscam_canvas_only.swf",
onTick: function(remain) {
if (0 == remain) {
jQuery("#status").text("Cheese!");
} else {
jQuery("#status").text(remain + " seconds remaining...");
}
},
onSave: function(data) {
var col = data.split(";");
var img = image;
for(var i = 0; i < 320; i++) {
var tmp = parseInt(col[i]);
img.data[pos + 0] = (tmp >> 16) & 0xff;
img.data[pos + 1] = (tmp >> 8) & 0xff;
img.data[pos + 2] = tmp & 0xff;
img.data[pos + 3] = 0xff;
pos+= 4;
}
if (pos >= 0x4B000) {
ctx.putImageData(img, 0, 0);
pos = 0;
}
},
onCapture: function () {
webcam.save();
jQuery("#flash").css("display", "block");
jQuery("#flash").fadeOut(100, function () {
jQuery("#flash").css("opacity", 1);
});
},
debug: function (type, string) {
jQuery("#status").html(type + ": " + string);
},
onLoad: function () {
var cams = webcam.getCameraList();
for(var i in cams) {
jQuery("#cams").append("<li>" + cams[i] + "</li>");
}
}
});
function getPageSize() {
var xScroll, yScroll;
if (window.innerHeight && window.scrollMaxY) {
xScroll = window.innerWidth + window.scrollMaxX;
yScroll = window.innerHeight + window.scrollMaxY;
} else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
xScroll = document.body.offsetWidth;
yScroll = document.body.offsetHeight;
}
var windowWidth, windowHeight;
if (self.innerHeight) { // all except Explorer
if(document.documentElement.clientWidth){
windowWidth = document.documentElement.clientWidth;
} else {
windowWidth = self.innerWidth;
}
windowHeight = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
} else if (document.body) { // other Explorers
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
}
// for small pages with total height less then height of the viewport
if(yScroll < windowHeight){
pageHeight = windowHeight;
} else {
pageHeight = yScroll;
}
// for small pages with total width less then width of the viewport
if(xScroll < windowWidth){
pageWidth = xScroll;
} else {
pageWidth = windowWidth;
}
return [pageWidth, pageHeight];
}
window.addEventListener("load", function() {
jQuery("body").append("<div id=\"flash\"></div>");
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
ctx = document.getElementById("canvas").getContext("2d");
ctx.clearRect(0, 0, 320, 240);
var img = new Image();
img.src = "logo.gif";
img.onload = function() {
ctx.drawImage(img, 129, 89);
}
image = ctx.getImageData(0, 0, 320, 240);
}
var pageSize = getPageSize();
jQuery("#flash").css({ height: pageSize[1] + "px" });
}, false);
window.addEventListener("resize", function() {
var pageSize = getPageSize();
jQuery("#flash").css({ height: pageSize[1] + "px" });
}, false);
I think I found the answer. I was initially trying to run the code from a folder location on my system. But when I deployed the same code to a local web application running on tomcat (http://<>/webcam/webcam.html), it started working in chrome!! I was anyhow going to deploy the code tomorrow on a remote server but had no idea that the webcam APIs would be inaccessible from the system if the application is not running on a server. Quite strange, but this saved me!!

Search functionality for D3 bundle layout

I'm a noob and trying to implement a search method for a diagram.
The diagram is a chord diagram and was mostly adapted from here:
http://bl.ocks.org/mbostock/1044242
And the search function was taken from here:
http://mbostock.github.io/protovis/ex/treemap.html
My problem is that when it reads my file it interprets the text as: [object SVGTextElement] and so the only hit I have for my search is if I search [object SVGTextElement].
This is my entire code:
<html>
<head>
<title>I'm Cool</title>
<link rel="stylesheet" type="text/css" href="ex.css?3.2"/>
<script type="text/javascript" src="../protovis-r3.2.js"></script>
<script type="text/javascript" src="bla3.json"></script>
<style type="text/css">
.node {
font: 300 11px "Helvetica Neue", Helvetica, Arial, sans-serif;
fill: #bbb;
}
.node:hover {
fill: #000;
}
.link {
stroke: steelblue;
stroke-opacity: 0.4;
fill: none;
pointer-events: none;
}
.node:hover,
.node--source,
.node--target {
font-weight: 700;
}
.node--source {
fill: #2ca02c;
}
.node--target {
fill: #d62728;
}
.link--source,
.link--target {
stroke-opacity: 1;
stroke-width: 2px;
}
.link--source {
stroke: #d62728;
}
.link--target {
stroke: #2ca02c;
}
#fig {
width: 860px;
}
#footer {
font: 24pt helvetica neue;
color: #666;
}
input {
font: 24pt helvetica neue;
background: none;
border: none;
outline: 0;
}
#title {
float: right;
text-align: right;
}
</style>
<body><div id="center"><div id="fig">
<div id="title"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var diameter = 800,
radius = diameter / 2,
innerRadius = radius - 160;
var cluster = d3.layout.cluster()
.size([360, innerRadius])
.sort(null)
.value(function(d) { return d.size; });
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(.85)
.radius(function(d) { return d.y; })
.angle(function(d) { return d.x / 180 * Math.PI; });
var svg = d3.select("body").append("svg")
.attr("width", diameter)
.attr("height", diameter)
.append("g")
.attr("transform", "translate(" + radius + "," + radius + ")");
var link = svg.append("g").selectAll(".link"),
node = svg.append("g").selectAll(".node");
d3.json("bla3.json", function(error, classes) {
var nodes = cluster.nodes(packageHierarchy(classes)),
links = packageImports(nodes);
link = link
.data(bundle(links))
.enter().append("path")
.each(function(d) { d.source = d[0], d.target = d[d.length - 1]; })
.attr("class", "link")
.attr("d", line);
node = node
.data(nodes.filter(function(n) { return !n.children; }))
.enter().append("text")
.attr("class", "node")
.attr("dx", function(d) { return d.x < 180 ? 12 : -12; })
.attr("dy", ".31em")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")" + (d.x < 180 ? "" : "rotate(180)"); })
.style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.text(function(d) { return d.key; })
.on("mouseover", mouseovered)
.on("mouseout", mouseouted);
});
function mouseovered(d) {
node
.each(function(n) { n.target = n.source = false; });
link
.classed("link--target", function(l) { if (l.target === d) return l.source.source = true; })
.classed("link--source", function(l) { if (l.source === d) return l.target.target = true; })
.filter(function(l) { return l.target === d || l.source === d; })
.each(function() { this.parentNode.appendChild(this); });
node
.classed("node--target", function(n) { return n.target; })
.classed("node--source", function(n) { return n.source; });
}
function mouseouted(d) {
link
.classed("link--target", false)
.classed("link--source", false);
node
.classed("node--target", false)
.classed("node--source", false);
}
d3.select(self.frameElement).style("height", diameter + "px");
// Lazily construct the package hierarchy from class names.
function packageHierarchy(classes) {
var map = {};
function find(name, data) {
var node = map[name], i;
if (!node) {
node = map[name] = data || {name: name, children: []};
if (name.length) {
node.parent = find(name.substring(0, i = name.lastIndexOf(".")));
node.parent.children.push(node);
node.key = name.substring(i + 1);
}
}
return node;
}
classes.forEach(function(d) {
find(d.name, d);
});
return map[""];
}
// Return a list of imports for the given array of nodes.
function packageImports(node) {
var map = {},
imports = [];
// Compute a map from name to node.
node.forEach(function(d) {
map[d.name] = d;
});
// For each import, construct a link from the source to target node.
node.forEach(function(d) {
if (d.imports) d.imports.forEach(function(i) {
imports.push({source: map[d.name], target: map[i]});
});
});
return imports;
}
function title(d) {
return d.parentNode ? (title(d.parentNode) + "." + d.nodeName) : d.nodeName;
}
var re = "",
color = pv.Colors.category19().by(function(d) d.parentNode.nodeName)
node = pv.dom(bla3).root("bla3.json").node();
var vis = new pv.Panel()
.width(860)
.height(568);
cluster.bundle.add(pv.Panel)
.fillStyle(function(d) color(d).alpha(title(d).match(re) ? 1 : .2))
.strokeStyle("#fff")
.lineWidth(1)
.antialias(false);
cluster.bundle.add(pv.Label)
.textStyle(function(d) pv.rgb(0, 0, 0, title(d).match(re) ? 1 : .2));
vis.render();
/** Counts the number of matching classes, updating the title element. */
function count() {
var classes = 0, bytes = 0, total = 0;
for (var i = 0; i < node.length; i++) {
var n = node[i];
if(n.firstChild) continue;
total += n.nodeValue;
if (title(n).match(re)) {
classes++;
bytes += n.nodeValue;
}
}
var percent = bytes / total * 100;
document.getElementById("title").innerHTML
= classes + " classes found "+n;
}
/** Updates the visualization and count when a new query is entered. */
function update(query) {
if (query != re) {
re = new RegExp(query, "i");
count();
vis.render();
}
}
count();
</script>
<div id="footer">
<label for="search">search: </label>
<input type="text" id="search" onkeyup="update(this.value)">
</div>
</div></div></body>
</html>
The input is bla3.json and looks like this:
[{"name":"A.Patient Intake","imports":["E.Name","C.injury","E.DOB","E.Email","Progress","B.Obtain Brief Medical History","Perform Physical Exam","Perform Subjective Patient Evaluation"]},
{"name":"C.injury","imports":[]},
{"name":"E.Name","imports":[]},
{"name":"E.Email","imports":[]},
...
I didn't put the whole thing but it shouldn't matter...
My purpose is of course to have a search function that I could type, for example, "Patient Intake" and it will highlight that chord (or just the name):
Any ideas of how to go about this?
I would approach this in a completely different way to what you're currently doing. I would filter the data based on the query (not the DOM elements) and then use D3's data matching to determine what to highlight. In code, this would look something like this.
function update(query) {
if (query != re) {
re = new RegExp(query, "i");
var matching = classes.filter(function(d) { return d.name.match(re); });
d3.selectAll("text.node").data(matching, function(d) { return d.name; })
// do something with the nodes
// can be source or target in links, so we use a different method here
links.filter(function(d) {
var ret = false;
matching.forEach(function(e) {
ret = ret || e.name == d.source.name || e.name == d.target.name;
});
return ret;
})
// do something with the links
}
}