Published
Edited
Dec 12, 2019
2 stars
Insert cell
md`# Weather Panel`
Insert cell
Insert cell
config = {
let group=[
{id:"gauge1" , value:250, xtype:"weather", x:50, y:50, repaint:1},
];
vzPanel.updateAll(group);
return group ;
}
Insert cell
shapeStore ={
let xtype = {}
xtype.weather = function(){
var obj = {};
var d_names = ["Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
var day_width=100, day_height=100;
var show_days = 7 ;
var icon = weather_icon;
obj.updateShape = function(node,config){
d3.select(node).selectAll("*").remove();
this.render(node,config) ;
};
obj.updateValue = function(node,v){
node.value = v;
//d3.select(node).select("rect").attr("width", v ) ;
};
/*
obj.render_test = function(node,config){
node.config = {}
var weather_data = {}
var data= d3.json("https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/aa1fa4b68a134fbb2ee9beb703e07a7e/23.0109,120.666?extend=hourly",
function(error, json) {
console.log('aaa')
console.log(json);
return;
if (error) throw error;
console.log(json);
weather_data = JSON.parse(json);
node.config.weather_data = weather_data;
obj.render2(node,config) ;
});
}
*/
obj.render = function(node,config){
node.config = {} ;
node.config.day_width = day_width ;
node.config.day_height = day_height ;
node.config.precipitationScale = d3.scaleLinear().domain([0, 1]).range([0, day_height]);
var weather_data = weather_data_now ; //node.config.weather_data ;
var g=d3.select(node).attr("transform","translate("+[config.x,config.y]+")");
//currently
var currently_data = [weather_data.currently] ;
g.selectAll("g.currently")
.data(currently_data)
.enter()
.append("g")
.attr("class","currently")
.each(function(d,i){
buildCurrently.call(this,node,d,i)
})
;
//weekly display
var daily_data = weather_data.daily.data ;
var weelyg = g.append("g")
.attr("class","weekly")
.attr("transform","translate(0,200)")
;
weelyg.append("rect")
.attr("width",day_width*d3.min([show_days,daily_data.length]))
.attr("height",day_height)
.attr("style","stroke-width:1px;stroke:#fff");
weelyg.selectAll("g.daily")
.data(daily_data)
.enter()
.append("g")
.attr("class","daily")
.each(function(d,i){
buildDaily.call(this,node,d,i)
})
;
this.updateValue(node,config.value);
};
function buildCurrently(node,d,i) {
var date = new Date() ; //new Date(d.time*1000);
var h = date.getHours();
var m = date.getMinutes();
var curr_date = date.getDate();
var curr_month = date.getMonth();
var curr_day = date.getDay();
var g=d3.select(this);
//currently time
g.append("text")
.attr("x", 700 )
.attr("y", 20)
.attr("text-anchor","end")
.attr("fill","#fff")
.attr("font-size",40)
.text(h+ ":"+ m)
;
g.append("text")
.attr("x", 700 )
.attr("y", 40)
.attr("text-anchor","end")
.attr("fill","#fff")
.attr("font-size",20)
.text(d_names[curr_day]+ " "+ curr_month + "/" + curr_date )
;
//temperature
var tempg = g.append("g")
.attr("class","currTemp")
.attr("transform","translate(120,80)")
.attr("stroke","#fff")
.attr("fill","none")
tempg.append("circle")
.attr("r",90)
.attr("stroke-width",2)
tempg.append("circle")
.attr("r",85)
.attr("stroke-width",10)
.attr("stroke","#ffc107")
tempg.append("circle")
.attr("r",80)
.attr("stroke-width",2)
tempg.append("circle")
.attr("r",75)
.attr("stroke-width",1)
.attr("stroke","#535353")
tempg.append("text")
.attr("y", 50)
.attr("text-anchor","middle")
.attr("fill","#fff")
.attr("font-size",64)
.text( fToC(d.temperature) )
tempg.append("text")
.attr("y", 68)
.attr("text-anchor","middle")
.attr("fill","#fff")
.attr("font-size",18)
.text( '\xB0C' )
//icon
tempg.append("g")
.attr("fill","#fff")
.attr("stroke-width",1)
.attr("stroke","#fff")
.attr("transform","scale(1.5) translate(0,-15)")
.html(icon[d.icon])
;
var second_data = [
{id:"wind",translate:[300,85],value:d.windSpeed,unit:"MPS"},
{id:"rain",translate:[450,85],value: Math.round(d.precipProbability*100),unit:"%"},
{id:"humidity2",translate:[600,85],value: Math.round(d.humidity*100),unit:"%"}
] ;
g.selectAll("g.currSecond")
.data(second_data)
.enter()
.append("g")
.attr("class","currSecond")
.attr("transform", d=>`translate(${d.translate})`)
.each(function(d,i){
buildCurrentlySecond.call(this,node,d,i)
});
}
function buildCurrentlySecond(node,d,i) {
var g = d3.select(this);
g.append("circle")
.attr("r",30)
.attr("stroke-width",6)
.attr("stroke","#535353")
;
g.append("circle")
.attr("r",28)
.attr("stroke-width",3)
.attr("stroke","#ffffff")
;
g.append("g")
.attr("fill","#fff")
.attr("stroke-width",1)
.attr("stroke","#fff")
.attr("transform","scale(0.8) translate(0,7)")
.html(icon[d.id])
;
g.append("text")
.attr("y", 60)
.attr("text-anchor","middle")
.attr("fill","#fff")
.attr("font-size",32)
.text( d.value )
;
g.append("text")
.attr("y", 80)
.attr("text-anchor","middle")
.attr("fill","#fff")
.attr("font-size",14)
.text( d.unit )
;
}
function buildDaily(node,d,i) {
if(i>=show_days) return;

var date = new Date(d.time*1000);
var curr_date = date.getDate();
var curr_month = date.getMonth();
var curr_day = date.getDay();
var g=d3.select(this);
var day_width = node.config.day_width ;
var day_height = node.config.day_height ;
var preciProbScale = node.config.precipitationScale ;
var preciRateY = preciProbScale(d.precipProbability) ;
//background
g.append("rect")
.attr("x", day_width*i )
.attr("y", 0)
.attr("fill", i%2?"#4a4a4a":"#353535")
.attr("width", day_width)
.attr("height", day_height)
;
//precipitation probability
g.append("rect")
.attr("x", day_width*i )
.attr("y", day_height - preciRateY)
.attr("fill","#358ad8")
.attr("width", day_width)
.attr("height", preciRateY)
;
//day
g.append("text")
.attr("x", day_width*i + day_width/2 )
.attr("y", 15)
.attr("text-anchor","middle")
.attr("fill","#fff")
.attr("font-size",14)
.text(d_names[curr_day])
//icon
g.append("g")
.attr("class","icon-weather")
.attr("transform","translate("+[day_width*i+day_width/2,day_height/2]+")")
.attr("fill","#FcFcFc")
//.html(icon.test)
.html(icon[d.icon]?icon[d.icon]:"")
;
g.append("g")
.attr("class","icon-temperature")
.attr("transform","translate("+[day_width*i + day_width/2 - 56,68]+") scale(0.30)")
.attr("fill", "#FcFcFc")
.html(icon.temperature )
;

g.append("g")
.attr("class","icon-humidity")
.attr("transform","translate("+[day_width*i + day_width/2, 80]+") scale(0.18,0.18)")
.attr("fill", "#FcFcFc")
.html(icon.humidity )
;
// tempture
g.append("text")
.attr("x", day_width*i + day_width/2 - 20)
.attr("y", 80)
.attr("text-anchor","middle")
.attr("fill","#fff")
.attr("font-size",14)
.text( fToC(d.temperatureHigh) + '\xB0C' )
g.append("text")
.attr("x", day_width*i + day_width/2 - 20)
.attr("y", 95)
.attr("text-anchor","middle")
.attr("fill","#fff")
.attr("font-size",14)
.text( fToC(d.temperatureLow)+ '\xB0C')
// humidity
g.append("text")
.attr("x", day_width*i + day_width/2 + 30)
.attr("y", 95)
.attr("text-anchor","middle")
.attr("fill","#fff")
.attr("font-size",14)
.text( Math.floor(d.humidity*100)+ '%')
}
function cToF(celsius)
{
var cTemp = celsius;
var cToFahr = cTemp * 9 / 5 + 32;
return Math.round(cToFahr);
var message = cTemp+'\xB0C is ' + cToFahr + ' \xB0F.';
console.log(message);
}

function fToC(fahrenheit)
{
var fTemp = fahrenheit;
var fToCel = (fTemp - 32) * 5 / 9;
return Math.round(fToCel);
var message = fTemp+'\xB0F is ' + fToCel + '\xB0C.';
console.log(message);
}
return obj;
}();
return xtype
}
Insert cell
Insert cell
Insert cell
weather_data_now =d3.json("https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/aa1fa4b68a134fbb2ee9beb703e07a7e/23.0109,120.666?extend=hourly")
Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more