I want to create a waveform with progress bars that fill with another color from left to right.
Right now it looks:
I want it to look like this. Yellow is buffered audio, orange is playing right now. I already have these values.
The main question is how do I fill each rect with color by currentTime of audio?
Here's my code:
const elementWidth = 1100
const elementHeight = 64
const duration = 160
const currentTime = 20
const buffered = 140
// here's data that i get from web audio api
// bar length in seconds would be:
// duration / renderData = how much seconds in one bar
const renderData = [
[-0.015067690176936956, 0.015065840696712662],
[-0.009963374263646985, 0.009960838406137254],
[-0.0329772714073922, 0.032922178973984494],
[-0.02010780853750818, 0.020192897509204638],
[-0.029141768346505944, 0.02913273608186522],
[-0.03390369982419367, 0.033888949138664096],
[-0.05309944789682607, 0.053106191954295334],
[-0.017992382356680794, 0.0179506794436456],
[-0.04118192967225779, 0.04120773269527067],
[-0.032132343283569134, 0.03223372926977138],
[-0.04340663941189386, 0.043317410948806916],
[-0.026866048759920942, 0.02695383570549558],
[-0.041548487297645216, 0.04142889765358134],
[-0.0512541217270734, 0.05128097373670754],
[-0.02645596673127562, 0.026461825339764114],
[-0.03276659370022165, 0.032869462727325334],
[-0.02983164709570332, 0.02965126735342542],
[-0.06186988270590101, 0.06228762507639405],
[-0.037202475771159274, 0.03684529067849468],
[-0.04496168984286248, 0.044984343262096924],
[-0.02961698097048877, 0.029580527280458145],
[-0.06637895360455075, 0.06584970915134748],
[-0.03966561332234608, 0.04028105442218536],
[-0.04888827685580639, 0.04879637577182824],
[-0.034440279218927505, 0.03448690299802526],
[-0.04076603383847427, 0.04087949817166488],
[-0.03422100968150345, 0.03407137586231854],
[-0.03420552026962888, 0.034233479991186845],
[-0.06124921943975816, 0.06133406711072517],
[-0.08080063612343565, 0.08052139740352077],
[-0.052296123826832304, 0.05245498821828788],
[-0.07728568068325997, 0.0772439557897976],
[-0.04070025960953707, 0.04072465208052425],
[-0.016598400103531252, 0.01673240062886387],
[-0.0495708419979178, 0.04952405213368158],
[-0.03402468183819489, 0.03404496946468417],
[-0.04719791564971553, 0.04716565090961255],
[-0.024305039710776202, 0.024425998358774473],
[-0.04539290174457686, 0.0453603392364138],
[-0.04291280211166326, 0.042803252613569195],
[-0.03237617188947045, 0.032430479168267405],
[-0.046939414609483046, 0.046991124408919255],
[-0.037727014544829074, 0.03756628029896137],
[-0.05813820211592722, 0.058137499737658825],
[-0.03306609736616569, 0.03332803022833292],
[-0.03706343131822335, 0.03699838219166897],
[-0.031640843865570666, 0.03150685332686255],
[-0.07978720110560034, 0.07982405111308474],
[-0.04565408283291298, 0.04548542047551325],
[-0.03838929844552628, 0.0386080775422541],
[-0.0349069030273341, 0.03516624962570975],
[-0.05791808093217102, 0.057646960595115364],
[-0.040111244425499945, 0.040190047578908046],
[-0.0421531094659709, 0.04210734133509555],
[-0.04358563889018587, 0.043380678911277275],
[-0.024025454017633886, 0.024179111399202893],
[-0.039038574013751944, 0.03889745017750074],
[-0.02962543563292595, 0.02975662299643922],
[-0.07215596460653108, 0.07225534620830149],
[-0.0845103969948925, 0.08417566858032748],
[-0.05029865141667644, 0.05110349428845409],
[-0.06766253837563593, 0.06680008803627584],
[-0.05413748268128195, 0.054261121431710246],
[-0.04702217202288801, 0.04710783667779247],
[-0.047177278676382065, 0.047241381909344966],
[-0.04949906253183499, 0.049358880485210296],
[-0.06384145451618915, 0.06398437795989458],
[-0.0532812223855561, 0.05336013656088595],
[-0.055032831282645335, 0.055131815418379866],
[-0.05771727930777607, 0.05743980672281111],
[-0.06865421948220482, 0.06896493506959074],
[-0.05163944571854085, 0.05129081551014095],
[-0.04546664828758613, 0.04549366890782257],
[-0.02196073923070452, 0.022119579288034315],
[-0.026824862238895183, 0.026915318981447094],
[-0.04771898452983383, 0.04768769589918763],
[-0.05221904154341058, 0.05202229643239835],
[-0.04034726803191834, 0.040288317010035164],
[-0.04252634158686052, 0.04275796625513488],
[-0.055381424446109724, 0.05515857756430962],
[-0.06160043085044191, 0.06143890271068376],
[-0.04579617210990365, 0.04612433751815954],
[-0.039244869887493206, 0.03927668403684328],
[-0.03426885260996771, 0.03423936180141113],
[-0.03516869910983574, 0.035127711830890515],
[-0.026964357386084752, 0.02699723933039285],
[-0.03816966714682839, 0.03778890745758835],
[-0.04777519168041681, 0.04824239079542675],
[-0.07617805358108933, 0.07612545525147858],
[-0.047140552370394925, 0.04744151736320112],
[-0.05137018378775051, 0.051114804207469784],
[-0.03259493948312707, 0.0325308332802452],
[-0.05715909221362399, 0.05709963073119724],
[-0.04835633252739353, 0.04849600527981289],
[-0.0433886628912617, 0.04331087342221564],
[-0.05191740499328957, 0.05183144200010501],
[-0.022690824730811025, 0.02281282548488598],
[-0.021657892287654815, 0.02160585204290785],
[-0.019911292276869504, 0.01990373441321122],
[-0.05252214322669061, 0.052514338488489534],
[-0.045757900781809524, 0.04581189437809006],
[-0.02396372548560904, 0.023788207356191405],
[-0.053426097224355276, 0.05348064888976746],
[-0.05394891160261981, 0.05421456735805457],
[-0.05251658416178273, 0.05238904616093791],
[-0.04774168806444406, 0.047755594530669916],
[-0.03506924339896615, 0.035076784816174336],
[-0.044288649573623336, 0.044337743067559894],
[-0.05109649028135573, 0.050986769978167874],
[-0.03986396401411081, 0.03992226520835857],
[-0.06271544843396921, 0.0628629998182233],
[-0.060325113831802425, 0.06014867491287253],
[-0.06409607265208252, 0.06426716029136537],
[-0.02890807357828784, 0.02879981209701445],
[-0.0579076968762734, 0.058055472378755635],
[-0.0788244096514242, 0.07889209396389751],
[-0.05489594835332056, 0.054304463238473114],
[-0.05066376350430718, 0.051136225666937284],
[-0.04324084422009672, 0.043106921303429975],
[-0.03618639085199314, 0.03630391952984575],
[-0.03229893887218463, 0.032254130211298596],
[-0.040388961018727465, 0.04034166483632292],
[-0.06891322548088202, 0.06894551548689337],
[-0.05708462516274434, 0.05713687370165375],
[-0.0908320094478539, 0.09053809343169553],
[-0.06997210675874246, 0.07036387396569341],
[-0.027676689451677956, 0.02757377175784071],
[-0.02882633060378825, 0.029207481257562274],
[-0.0414701765332311, 0.04136630655327525],
[-0.05308296364144847, 0.0526747543606357],
[-0.02724146501450132, 0.027406581699254588],
[-0.04265844625269343, 0.04270290902986972],
[-0.03899306746018118, 0.038745252551468795],
[-0.0552804734553083, 0.05535944558193926],
[-0.02309096284644189, 0.023040044134232315],
[-0.0507964500028555, 0.05096013747702334],
[-0.04123972706510699, 0.041359046982264745],
[-0.03236153261658939, 0.032179960855430505],
[-0.02858521671477931, 0.028570736354436077],
[-0.03515761112679279, 0.03513507691850391],
[-0.049852204843317816, 0.04984858000374448],
[-0.038280519845162314, 0.038365751907998916],
[-0.05489151074836156, 0.054958999808454506],
[-0.02552547302215947, 0.025555844960312334],
[-0.06393766191228746, 0.0638978766928521],
[-0.04140103340243134, 0.04113465467714282],
[-0.04647459357809104, 0.04654619117779597],
[-0.03293849813553063, 0.03301029011724379],
[-0.04428244235309984, 0.04433992273438912],
[-0.047489538949244604, 0.04755256034371833],
[-0.047176763166566854, 0.04719291045558167],
[-0.06353201748860114, 0.06380784207550017],
[-0.07775209195691819, 0.0773872824070752],
[-0.054300174262817344, 0.054476381979975085],
[-0.08808678703605805, 0.0879414485377677],
[-0.04016286323725983, 0.04007725752721749],
[-0.01889086923709467, 0.018989486049242103]
]
const height = d3.scaleLinear()
.domain(d3.extent(renderData.map(e => e[1] - e[0])))
.range([0, elementHeight])
d3.select(document.getElementById('app'))
.append('svg')
.attr('class', 'd3')
.attr('width', elementWidth)
.attr('height', elementHeight)
.selectAll('.bar')
.data(renderData)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('fill', '#E0E0E0')
.attr('x', (d, i) => (i * 2 + i))
.attr('y', d => elementHeight - height(d[1] - d[0]))
.transition()
.duration(300)
.ease(d3.easeLinear)
.attr('width', 2)
.attr('height', d => height(d[1] - d[0]))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id='app' />
</body>
</html>
Its really fun to play with svg :)
This is what i made, have a look.
const elementWidth = 1100
const elementHeight = 64
var audioTotalTime = 120.0000; // in secound
var currentTime = 0;
var currentBuffer = 0;
const renderData = [
[-0.015067690176936956, 0.015065840696712662],
[-0.009963374263646985, 0.009960838406137254],
[-0.0329772714073922, 0.032922178973984494],
[-0.02010780853750818, 0.020192897509204638],
[-0.029141768346505944, 0.02913273608186522],
[-0.03390369982419367, 0.033888949138664096],
[-0.05309944789682607, 0.053106191954295334],
[-0.017992382356680794, 0.0179506794436456],
[-0.04118192967225779, 0.04120773269527067],
[-0.032132343283569134, 0.03223372926977138],
[-0.04340663941189386, 0.043317410948806916],
[-0.026866048759920942, 0.02695383570549558],
[-0.041548487297645216, 0.04142889765358134],
[-0.0512541217270734, 0.05128097373670754],
[-0.02645596673127562, 0.026461825339764114],
[-0.03276659370022165, 0.032869462727325334],
[-0.02983164709570332, 0.02965126735342542],
[-0.06186988270590101, 0.06228762507639405],
[-0.037202475771159274, 0.03684529067849468],
[-0.04496168984286248, 0.044984343262096924],
[-0.02961698097048877, 0.029580527280458145],
[-0.06637895360455075, 0.06584970915134748],
[-0.03966561332234608, 0.04028105442218536],
[-0.04888827685580639, 0.04879637577182824],
[-0.034440279218927505, 0.03448690299802526],
[-0.04076603383847427, 0.04087949817166488],
[-0.03422100968150345, 0.03407137586231854],
[-0.03420552026962888, 0.034233479991186845],
[-0.06124921943975816, 0.06133406711072517],
[-0.08080063612343565, 0.08052139740352077],
[-0.052296123826832304, 0.05245498821828788],
[-0.07728568068325997, 0.0772439557897976],
[-0.04070025960953707, 0.04072465208052425],
[-0.016598400103531252, 0.01673240062886387],
[-0.0495708419979178, 0.04952405213368158],
[-0.03402468183819489, 0.03404496946468417],
[-0.04719791564971553, 0.04716565090961255],
[-0.024305039710776202, 0.024425998358774473],
[-0.04539290174457686, 0.0453603392364138],
[-0.04291280211166326, 0.042803252613569195],
[-0.03237617188947045, 0.032430479168267405],
[-0.046939414609483046, 0.046991124408919255],
[-0.037727014544829074, 0.03756628029896137],
[-0.05813820211592722, 0.058137499737658825],
[-0.03306609736616569, 0.03332803022833292],
[-0.03706343131822335, 0.03699838219166897],
[-0.031640843865570666, 0.03150685332686255],
[-0.07978720110560034, 0.07982405111308474],
[-0.04565408283291298, 0.04548542047551325],
[-0.03838929844552628, 0.0386080775422541],
[-0.0349069030273341, 0.03516624962570975],
[-0.05791808093217102, 0.057646960595115364],
[-0.040111244425499945, 0.040190047578908046],
[-0.0421531094659709, 0.04210734133509555],
[-0.04358563889018587, 0.043380678911277275],
[-0.024025454017633886, 0.024179111399202893],
[-0.039038574013751944, 0.03889745017750074],
[-0.02962543563292595, 0.02975662299643922],
[-0.07215596460653108, 0.07225534620830149],
[-0.0845103969948925, 0.08417566858032748],
[-0.05029865141667644, 0.05110349428845409],
[-0.06766253837563593, 0.06680008803627584],
[-0.05413748268128195, 0.054261121431710246],
[-0.04702217202288801, 0.04710783667779247],
[-0.047177278676382065, 0.047241381909344966],
[-0.04949906253183499, 0.049358880485210296],
[-0.06384145451618915, 0.06398437795989458],
[-0.0532812223855561, 0.05336013656088595],
[-0.055032831282645335, 0.055131815418379866],
[-0.05771727930777607, 0.05743980672281111],
[-0.06865421948220482, 0.06896493506959074],
[-0.05163944571854085, 0.05129081551014095],
[-0.04546664828758613, 0.04549366890782257],
[-0.02196073923070452, 0.022119579288034315],
[-0.026824862238895183, 0.026915318981447094],
[-0.04771898452983383, 0.04768769589918763],
[-0.05221904154341058, 0.05202229643239835],
[-0.04034726803191834, 0.040288317010035164],
[-0.04252634158686052, 0.04275796625513488],
[-0.055381424446109724, 0.05515857756430962],
[-0.06160043085044191, 0.06143890271068376],
[-0.04579617210990365, 0.04612433751815954],
[-0.039244869887493206, 0.03927668403684328],
[-0.03426885260996771, 0.03423936180141113],
[-0.03516869910983574, 0.035127711830890515],
[-0.026964357386084752, 0.02699723933039285],
[-0.03816966714682839, 0.03778890745758835],
[-0.04777519168041681, 0.04824239079542675],
[-0.07617805358108933, 0.07612545525147858],
[-0.047140552370394925, 0.04744151736320112],
[-0.05137018378775051, 0.051114804207469784],
[-0.03259493948312707, 0.0325308332802452],
[-0.05715909221362399, 0.05709963073119724],
[-0.04835633252739353, 0.04849600527981289],
[-0.0433886628912617, 0.04331087342221564],
[-0.05191740499328957, 0.05183144200010501],
[-0.022690824730811025, 0.02281282548488598],
[-0.021657892287654815, 0.02160585204290785],
[-0.019911292276869504, 0.01990373441321122],
[-0.05252214322669061, 0.052514338488489534],
[-0.045757900781809524, 0.04581189437809006],
[-0.02396372548560904, 0.023788207356191405],
[-0.053426097224355276, 0.05348064888976746],
[-0.05394891160261981, 0.05421456735805457],
[-0.05251658416178273, 0.05238904616093791],
[-0.04774168806444406, 0.047755594530669916],
[-0.03506924339896615, 0.035076784816174336],
[-0.044288649573623336, 0.044337743067559894],
[-0.05109649028135573, 0.050986769978167874],
[-0.03986396401411081, 0.03992226520835857],
[-0.06271544843396921, 0.0628629998182233],
[-0.060325113831802425, 0.06014867491287253],
[-0.06409607265208252, 0.06426716029136537],
[-0.02890807357828784, 0.02879981209701445],
[-0.0579076968762734, 0.058055472378755635],
[-0.0788244096514242, 0.07889209396389751],
[-0.05489594835332056, 0.054304463238473114],
[-0.05066376350430718, 0.051136225666937284],
[-0.04324084422009672, 0.043106921303429975],
[-0.03618639085199314, 0.03630391952984575],
[-0.03229893887218463, 0.032254130211298596],
[-0.040388961018727465, 0.04034166483632292],
[-0.06891322548088202, 0.06894551548689337],
[-0.05708462516274434, 0.05713687370165375],
[-0.0908320094478539, 0.09053809343169553],
[-0.06997210675874246, 0.07036387396569341],
[-0.027676689451677956, 0.02757377175784071],
[-0.02882633060378825, 0.029207481257562274],
[-0.0414701765332311, 0.04136630655327525],
[-0.05308296364144847, 0.0526747543606357],
[-0.02724146501450132, 0.027406581699254588],
[-0.04265844625269343, 0.04270290902986972],
[-0.03899306746018118, 0.038745252551468795],
[-0.0552804734553083, 0.05535944558193926],
[-0.02309096284644189, 0.023040044134232315],
[-0.0507964500028555, 0.05096013747702334],
[-0.04123972706510699, 0.041359046982264745],
[-0.03236153261658939, 0.032179960855430505],
[-0.02858521671477931, 0.028570736354436077],
[-0.03515761112679279, 0.03513507691850391],
[-0.049852204843317816, 0.04984858000374448],
[-0.038280519845162314, 0.038365751907998916],
[-0.05489151074836156, 0.054958999808454506],
[-0.02552547302215947, 0.025555844960312334],
[-0.06393766191228746, 0.0638978766928521],
[-0.04140103340243134, 0.04113465467714282],
[-0.04647459357809104, 0.04654619117779597],
[-0.03293849813553063, 0.03301029011724379],
[-0.04428244235309984, 0.04433992273438912],
[-0.047489538949244604, 0.04755256034371833],
[-0.047176763166566854, 0.04719291045558167],
[-0.06353201748860114, 0.06380784207550017],
[-0.07775209195691819, 0.0773872824070752],
[-0.054300174262817344, 0.054476381979975085],
[-0.08808678703605805, 0.0879414485377677],
[-0.04016286323725983, 0.04007725752721749],
[-0.01889086923709467, 0.018989486049242103]
]
const height = d3.scaleLinear()
.domain(d3.extent(renderData.map(e => e[1] - e[0])))
.range([0, elementHeight])
d3.select(document.getElementById('app'))
.append('svg')
.attr('class', 'd3')
.attr('width', elementWidth)
.attr('height', elementHeight)
.selectAll('.bar')
.data(renderData)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('fill', '#E0E0E0')
.attr('x', (d, i) => (i * 2 + i))
.attr('y', d => elementHeight - height(d[1] - d[0]))
.transition()
.duration(300)
.ease(d3.easeLinear)
.attr('width', 2)
.attr('height', d => height(d[1] - d[0]))
var svg = $(".d3");
var lng = svg.find("rect").length;
function update(){
var selectedRect = Math.floor(((currentTime ) / ( lng )) * (audioTotalTime + 86));
var selectedBufferRect = Math.floor(((currentBuffer ) / ( lng )) * (audioTotalTime + 86));
// this is the best i could do, but you understand the ide
var playingColor = "red";
var bufferColor = "green";
// buffer Progress
$.each (svg.find("rect"), function(index, i){ // buffer
if (index<= selectedBufferRect &&$(this).attr("fill") != playingColor )
$(this).attr("fill", bufferColor);
});
// Playing Progress
$.each (svg.find("rect"), function(index, i){ // Playing
if (index<= selectedRect)
$(this).attr("fill", playingColor);
});
}
function PlayingSimulator(){
currentTime += 1
currentBuffer +=3;
if (currentTime>= audioTotalTime){
update();
return false;
}
update();
setTimeout(PlayingSimulator, 60);
}
PlayingSimulator();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id='app' />
</body>
</html>
Just add some simple logic in function paint() to determine the fill color. Then you need need to decide how often to re-render (I guess at least once every second for updating currentTime).
const elementWidth = 1100;
const elementHeight = 64;
const duration = 160;
let currentTime = 0;
const buffered = 140;
const renderData = [[-0.015067690176936956, 0.015065840696712662],[-0.009963374263646985, 0.009960838406137254],[-0.0329772714073922, 0.032922178973984494],[-0.02010780853750818, 0.020192897509204638],[-0.029141768346505944, 0.02913273608186522],[-0.03390369982419367, 0.033888949138664096],[-0.05309944789682607, 0.053106191954295334],[-0.017992382356680794, 0.0179506794436456],[-0.04118192967225779, 0.04120773269527067],[-0.032132343283569134, 0.03223372926977138],[-0.04340663941189386, 0.043317410948806916],[-0.026866048759920942, 0.02695383570549558],[-0.041548487297645216, 0.04142889765358134],[-0.0512541217270734, 0.05128097373670754],[-0.02645596673127562, 0.026461825339764114],[-0.03276659370022165, 0.032869462727325334],[-0.02983164709570332, 0.02965126735342542],[-0.06186988270590101, 0.06228762507639405],[-0.037202475771159274, 0.03684529067849468],[-0.04496168984286248, 0.044984343262096924],[-0.02961698097048877, 0.029580527280458145],[-0.06637895360455075, 0.06584970915134748],[-0.03966561332234608, 0.04028105442218536],[-0.04888827685580639, 0.04879637577182824],[-0.034440279218927505, 0.03448690299802526],[-0.04076603383847427, 0.04087949817166488],[-0.03422100968150345, 0.03407137586231854],[-0.03420552026962888, 0.034233479991186845],[-0.06124921943975816, 0.06133406711072517],[-0.08080063612343565, 0.08052139740352077],[-0.052296123826832304, 0.05245498821828788],[-0.07728568068325997, 0.0772439557897976],[-0.04070025960953707, 0.04072465208052425],[-0.016598400103531252, 0.01673240062886387],[-0.0495708419979178, 0.04952405213368158],[-0.03402468183819489, 0.03404496946468417],[-0.04719791564971553, 0.04716565090961255],[-0.024305039710776202, 0.024425998358774473],[-0.04539290174457686, 0.0453603392364138],[-0.04291280211166326, 0.042803252613569195],[-0.03237617188947045, 0.032430479168267405],[-0.046939414609483046, 0.046991124408919255],[-0.037727014544829074, 0.03756628029896137],[-0.05813820211592722, 0.058137499737658825],[-0.03306609736616569, 0.03332803022833292],[-0.03706343131822335, 0.03699838219166897],[-0.031640843865570666, 0.03150685332686255],[-0.07978720110560034, 0.07982405111308474],[-0.04565408283291298, 0.04548542047551325],[-0.03838929844552628, 0.0386080775422541],[-0.0349069030273341, 0.03516624962570975],[-0.05791808093217102, 0.057646960595115364],[-0.040111244425499945, 0.040190047578908046],[-0.0421531094659709, 0.04210734133509555],[-0.04358563889018587, 0.043380678911277275],[-0.024025454017633886, 0.024179111399202893],[-0.039038574013751944, 0.03889745017750074],[-0.02962543563292595, 0.02975662299643922],[-0.07215596460653108, 0.07225534620830149],[-0.0845103969948925, 0.08417566858032748],[-0.05029865141667644, 0.05110349428845409],[-0.06766253837563593, 0.06680008803627584],[-0.05413748268128195, 0.054261121431710246],[-0.04702217202288801, 0.04710783667779247],[-0.047177278676382065, 0.047241381909344966],[-0.04949906253183499, 0.049358880485210296],[-0.06384145451618915, 0.06398437795989458],[-0.0532812223855561, 0.05336013656088595],[-0.055032831282645335, 0.055131815418379866],[-0.05771727930777607, 0.05743980672281111],[-0.06865421948220482, 0.06896493506959074],[-0.05163944571854085, 0.05129081551014095],[-0.04546664828758613, 0.04549366890782257],[-0.02196073923070452, 0.022119579288034315],[-0.026824862238895183, 0.026915318981447094],[-0.04771898452983383, 0.04768769589918763],[-0.05221904154341058, 0.05202229643239835],[-0.04034726803191834, 0.040288317010035164],[-0.04252634158686052, 0.04275796625513488],[-0.055381424446109724, 0.05515857756430962],[-0.06160043085044191, 0.06143890271068376],[-0.04579617210990365, 0.04612433751815954],[-0.039244869887493206, 0.03927668403684328],[-0.03426885260996771, 0.03423936180141113],[-0.03516869910983574, 0.035127711830890515],[-0.026964357386084752, 0.02699723933039285],[-0.03816966714682839, 0.03778890745758835],[-0.04777519168041681, 0.04824239079542675],[-0.07617805358108933, 0.07612545525147858],[-0.047140552370394925, 0.04744151736320112],[-0.05137018378775051, 0.051114804207469784],[-0.03259493948312707, 0.0325308332802452],[-0.05715909221362399, 0.05709963073119724],[-0.04835633252739353, 0.04849600527981289],[-0.0433886628912617, 0.04331087342221564],[-0.05191740499328957, 0.05183144200010501],[-0.022690824730811025, 0.02281282548488598],[-0.021657892287654815, 0.02160585204290785],[-0.019911292276869504, 0.01990373441321122],[-0.05252214322669061, 0.052514338488489534],[-0.045757900781809524, 0.04581189437809006],[-0.02396372548560904, 0.023788207356191405],[-0.053426097224355276, 0.05348064888976746],[-0.05394891160261981, 0.05421456735805457],[-0.05251658416178273, 0.05238904616093791],[-0.04774168806444406, 0.047755594530669916],[-0.03506924339896615, 0.035076784816174336],[-0.044288649573623336, 0.044337743067559894],[-0.05109649028135573, 0.050986769978167874],[-0.03986396401411081, 0.03992226520835857],[-0.06271544843396921, 0.0628629998182233],[-0.060325113831802425, 0.06014867491287253],[-0.06409607265208252, 0.06426716029136537],[-0.02890807357828784, 0.02879981209701445],[-0.0579076968762734, 0.058055472378755635],[-0.0788244096514242, 0.07889209396389751],[-0.05489594835332056, 0.054304463238473114],[-0.05066376350430718, 0.051136225666937284],[-0.04324084422009672, 0.043106921303429975],[-0.03618639085199314, 0.03630391952984575],[-0.03229893887218463, 0.032254130211298596],[-0.040388961018727465, 0.04034166483632292],[-0.06891322548088202, 0.06894551548689337],[-0.05708462516274434, 0.05713687370165375],[-0.0908320094478539, 0.09053809343169553],[-0.06997210675874246, 0.07036387396569341],[-0.027676689451677956, 0.02757377175784071],[-0.02882633060378825, 0.029207481257562274],[-0.0414701765332311, 0.04136630655327525],[-0.05308296364144847, 0.0526747543606357],[-0.02724146501450132, 0.027406581699254588],[-0.04265844625269343, 0.04270290902986972],[-0.03899306746018118, 0.038745252551468795],[-0.0552804734553083, 0.05535944558193926],[-0.02309096284644189, 0.023040044134232315],[-0.0507964500028555, 0.05096013747702334],[-0.04123972706510699, 0.041359046982264745],[-0.03236153261658939, 0.032179960855430505],[-0.02858521671477931, 0.028570736354436077],[-0.03515761112679279, 0.03513507691850391],[-0.049852204843317816, 0.04984858000374448],[-0.038280519845162314, 0.038365751907998916],[-0.05489151074836156, 0.054958999808454506],[-0.02552547302215947, 0.025555844960312334],[-0.06393766191228746, 0.0638978766928521],[-0.04140103340243134, 0.04113465467714282],[-0.04647459357809104, 0.04654619117779597],[-0.03293849813553063, 0.03301029011724379],[-0.04428244235309984, 0.04433992273438912],[-0.047489538949244604, 0.04755256034371833],[-0.047176763166566854, 0.04719291045558167],[-0.06353201748860114, 0.06380784207550017],[-0.07775209195691819, 0.0773872824070752],[-0.054300174262817344, 0.054476381979975085],[-0.08808678703605805, 0.0879414485377677],[-0.04016286323725983, 0.04007725752721749],[-0.01889086923709467, 0.018989486049242103]];
const height = d3
.scaleLinear()
.domain(d3.extent(renderData.map(e => e[1] - e[0])))
.range([0, elementHeight]);
const svg = d3
.select("#app")
.append("svg")
.attr("class", "d3")
.attr("width", elementWidth)
.attr("height", elementHeight);
const bar = svg.selectAll(".bar").data(renderData);
const barEnter = bar
.enter()
.append("rect")
.attr("class", "bar")
.attr("fill", (d, i) => {
return paint(i);
})
.attr("x", (d, i) => i * 2 + i)
.attr("y", d => elementHeight - height(d[1] - d[0]))
.attr("width", 2)
.attr("height", d => height(d[1] - d[0]));
function reRender() {
currentTime += 1
barEnter.attr("fill", (d, i) => {
return paint(i);
})
}
window.setInterval(function () {
reRender()
}, 1000);
function paint(i) {
barPos = i / renderData.length * duration;
if (barPos <= currentTime) {
return "red";
} else if (barPos <= buffered) {
return "orange";
} else {
return "grey";
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id='app' />
</body>
</html>
Codepen
Related
I am trying to create a plot that is pannable/zoomable only in the x and is responsive to the page resizes. I am running into an issue where the domain of the x-axis works properly at the original zoomTransform. Code snippet is below. I would suggest opening in a different window to test. Notice that the domain stays the same when the window is resized at the original state. Once the plot is panned any amount (the further you pan the more prominent the issue) the domain will shift on page resize.
I have tested trying to adjust the domain on x_ax to the value of the vd axis but that does not seem to help.
window.addEventListener("resize", redraw);
let parentRect = $("#i3061007142472").parent()[0].getBoundingClientRect();
let pWidth = parentRect.width;
let pHeight = parentRect.height;
var margin = {
'top': 10,
'right': 30,
'bottom': 30,
'left': 60
},
width = pWidth - margin.left - margin.right,
height = pHeight - margin.top - margin.bottom;
var svg = d3.select("#i3061007142472")
.attr("width", width)
.attr("height", height + 20);
var zoom = d3.zoom();
zoom.on("zoom", zoom_handler_dataplot);
d3.select("#i3061007142472").call(zoom);
var x_ax = d3.scaleTime()
.domain([new Date('0'), new Date('10')])
.range([60, width]);
x_ax.type = "time";
var svg_gX = svg.append("g")
.attr("class", "xAxis dataplot")
.attr("transform", `translate(0, ${height})`)
svg_gX.call(d3.axisBottom(x_ax).ticks(5));
var y_ax = d3.scaleLinear()
.domain([0, 10])
.range([height, 0]);
y_ax.type = "linear";
let vd_xaxis_ax = x_ax.copy();
let vd_yaxis_ax = y_ax.copy();
var svg_gY = svg.append("g")
.attr("class", "yAxis dataplot")
.style("padding-left", "50px")
.attr("transform", "translate(" + 60 + ", 0)")
.call(d3.axisLeft(y_ax).ticks(5));
allow_pan_dir = "x";
domain = x_ax.domain();
function zoom_handler_dataplot() {
if (allow_pan_dir != "none") {
if (allow_pan_dir == "x" || allow_pan_dir == "both") {
vd_xaxis_ax = d3.event.transform.rescaleX(x_ax);
domain = vd_xaxis_ax.domain()
svg_gX.call(d3.axisBottom(vd_xaxis_ax));
} else {
vd_xaxis_ax = x_ax;
}
if (allow_pan_dir == "y" || allow_pan_dir == "both") {
vd_yaxis_ax = d3.event.transform.rescaleY(y_ax);
svg_gY.call(d3.axisLeft(vd_yaxis_ax));
} else {
vd_yaxis_ax = y_ax;
}
}
}
function redraw() {
console.warn("calling redraw");
console.warn(allow_pan_dir);
chartWidth = parseInt(d3.select(".dataplot_i3061007142472").style("width"));
chartHeight = parseInt(d3.select(".dataplot_i3061007142472").style("height"));
height = chartHeight - margin.top - margin.bottom + 20;
x_ax.range([60, chartWidth]);
y_ax.range([chartHeight - 30 - 10 + 20, 0]);
if (allow_pan_dir == "x" || allow_pan_dir == "both") {
vd_xaxis_ax = d3.zoomTransform(d3.select("#i3061007142472").node()).rescaleX(x_ax);
svg_gX.call(d3.axisBottom(vd_xaxis_ax));
} else {
vd_xaxis_ax = x_ax;
}
if (allow_pan_dir == "y" || allow_pan_dir == "both") {
vd_yaxis_ax = d3.zoomTransform(d3.select("#i3061007142472").node()).rescaleY(y_ax);
svg_gY.call(d3.axisLeft(vd_yaxis_ax));
} else {
vd_yaxis_ax = y_ax;
}
let currTransform = d3.zoomTransform(d3.select('#i3061007142472').node());
d3.select("#i3061007142472").call(zoom.transform, currTransform);
}
<!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.0">
<link rel="stylesheet" href="./styles.css ">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.0.0/d3.min.js" integrity="sha512-il/oXcqETt5LGGmWWbOZLxrDgQQXlr7+ZI37ksA//3e9mxFloAOzlkF8SqtMOlWL6zTCk8hPYUQnreiQvT4elQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
</head>
<body>
<div id="my_plot" style="display: flex; flex: 1;">
<svg id="i3061007142472" class="dataplot_i3061007142472 dataplot"></svg>
</div>
<script src="./app.js"></script>
</body>
</html>
I am trying to create a simple plot that is zoomable, pannable, and dynamically resizes with the window. In this case I only want it be to zoomable and pannable on the x axis. I'm using d3 v4.
The main issue I have run into is that the domain of the bottom axis will shift/slide when the page is being resized after the plot has been transformed. On resizing without having first transformed the plot, the bottom axis behaves as desired and maintains its domain, just "compressing" and "expanding" on resize.
To see the desired behavior, you can resize the plot without first transforming the plot by zooming or panning, and you'll see that the bottom axis maintains its domain.
To see the undesirable behavior, you can pan or zoom the plot and then resize the page. You will notice that the domain of the bottom axis will slide/shift.
I suspect there is something I'm doing wrong with setting my scales, however I am quite stuck.
The snippet below is a minimum working example of what I am working with:
window.addEventListener("resize", redraw);
let parentRect = $("#i3061007142472").parent()[0].getBoundingClientRect();
let pWidth = parentRect.width;
let pHeight = parentRect.height;
var margin = {
'top': 10,
'right': 30,
'bottom': 30,
'left': 60
},
width = pWidth - margin.left - margin.right,
height = pHeight - margin.top - margin.bottom;
var svg = d3.select("#i3061007142472")
.attr("width", width)
.attr("height", height + 20);
var zoom = d3.zoom();
zoom.on("zoom", zoom_handler_dataplot);
d3.select("#i3061007142472").call(zoom);
var x_i3061007142472 = d3.scaleTime()
.domain([new Date('0'), new Date('10')])
.range([60, width]);
x_i3061007142472.type = "time";
var svg_gX = svg.append("g")
.attr("class", "xAxis dataplot")
.attr("transform", `translate(0, ${height})`)
svg_gX.call(d3.axisBottom(x_i3061007142472).ticks(5));
var y_i3061007142472 = d3.scaleLinear()
.domain([0, 10])
.range([height, 0]);
y_i3061007142472.type = "linear";
let vd_xaxis_i3061007142472 = x_i3061007142472.copy();
let vd_yaxis_i3061007142472 = y_i3061007142472.copy();
var svg_gY = svg.append("g")
.attr("class", "yAxis dataplot")
.style("padding-left", "50px")
.attr("transform", "translate(" + 60 + ", 0)")
.call(d3.axisLeft(y_i3061007142472).ticks(5));
allow_pan_dir = "x";
domain = x_i3061007142472.domain();
function zoom_handler_dataplot() {
if (allow_pan_dir != "none") {
if (allow_pan_dir == "x" || allow_pan_dir == "both") {
vd_xaxis_i3061007142472 = d3.event.transform.rescaleX(x_i3061007142472);
domain = vd_xaxis_i3061007142472.domain()
svg_gX.call(d3.axisBottom(vd_xaxis_i3061007142472));
} else {
vd_xaxis_i3061007142472 = x_i3061007142472;
}
if (allow_pan_dir == "y" || allow_pan_dir == "both") {
vd_yaxis_i3061007142472 = d3.event.transform.rescaleY(y_i3061007142472);
svg_gY.call(d3.axisLeft(vd_yaxis_i3061007142472));
} else {
vd_yaxis_i3061007142472 = y_i3061007142472;
}
}
}
function redraw() {
console.warn("calling redraw");
console.warn(allow_pan_dir);
chartWidth = parseInt(d3.select(".dataplot_i3061007142472").style("width"));
chartHeight = parseInt(d3.select(".dataplot_i3061007142472").style("height"));
height = chartHeight - margin.top - margin.bottom + 20;
x_i3061007142472.range([60, chartWidth]);
y_i3061007142472.range([chartHeight - 30 - 10 + 20, 0]);
if (allow_pan_dir == "x" || allow_pan_dir == "both") {
vd_xaxis_i3061007142472 = d3.zoomTransform(d3.select("#i3061007142472").node()).rescaleX(x_i3061007142472);
svg_gX.call(d3.axisBottom(vd_xaxis_i3061007142472));
} else {
vd_xaxis_i3061007142472 = x_i3061007142472;
}
if (allow_pan_dir == "y" || allow_pan_dir == "both") {
vd_yaxis_i3061007142472 = d3.zoomTransform(d3.select("#i3061007142472").node()).rescaleY(y_i3061007142472);
svg_gY.call(d3.axisLeft(vd_yaxis_i3061007142472));
} else {
vd_yaxis_i3061007142472 = y_i3061007142472;
}
let currTransform = d3.zoomTransform(d3.select('#i3061007142472').node());
d3.select("#i3061007142472").call(zoom.transform, currTransform);
}
<!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.0">
<link rel="stylesheet" href="./styles.css ">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.0.0/d3.min.js" integrity="sha512-il/oXcqETt5LGGmWWbOZLxrDgQQXlr7+ZI37ksA//3e9mxFloAOzlkF8SqtMOlWL6zTCk8hPYUQnreiQvT4elQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
</head>
<body>
<div id="my_plot" style="display: flex; flex: 1;">
<svg id="i3061007142472" class="dataplot_i3061007142472 dataplot"></svg>
</div>
<script src="./app.js"></script>
</body>
</html>
I tried changing the domain on resize to match the transformed, tried using an intermediary scale, tried modifying the reference scale.
Would there be an easy way to implement this addTooltip function from Mike Freeman's Plot Tooltip Notebook within a local vanilla JavaScript environment? In addition, what would be the best way to manage user input and interactivity with Plot locally? I realize Observable makes all of this a lot less painful to code. Was just hoping there would be solutions outside of the website. Or should I just go the D3.js route if I want to do these things?
<html>
<head>
<meta name=”robots” content=”noindex”>
<meta charset="UTF-8">
<title>Example Plots</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#observablehq/plot#0.4"></script>
</head>
<body>
<div >
<h1>Iris Dataset</h1>
<div id="chart1"></div>
</div>
</body>
<script type="module">
const iris = await d3.json("https://cdn.jsdelivr.net/npm/vega-datasets#1.31.1/data/iris.json");
const scatter = function(data) {
const div = document.getElementById("chart1")
div.appendChild(Plot.plot({
marks: [
Plot.dot(data, {x: "sepalLength", y: "sepalWidth", stroke: "species"}),
],
}));
}
scatter(iris)
</script>
</html>
As you can see in my example below, you just need to import the htl.html requirement and import (copy and paste) the addTooltips, hover and id_generator cells as functions.
<html>
<head>
<meta name=”robots” content=”noindex”>
<meta charset="UTF-8">
<title>Example Plots</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#observablehq/plot#0.4"></script>
<script src="https://cdn.jsdelivr.net/npm/htl#0.3.1/dist/htl.min.js"></script>
</head>
<body>
<div >
<h1>Iris Dataset</h1>
<div id="chart1"></div>
</div>
</body>
<script type="module">
const iris = await d3.json("https://cdn.jsdelivr.net/npm/vega-datasets#1.31.1/data/iris.json");
const html = htl.html
function scatter(data) {
const div = document.getElementById("chart1")
div.appendChild(addTooltips(Plot.plot({
marks: [
Plot.dot(data, {x: "sepalLength", y: "sepalWidth", stroke: "species",
title: (d) =>
`${d.species} \n Sepal Length: ${d.sepalLength} \n Sepal Width: ${d.sepalWidth}`
}),
],
})))
}
function addTooltips(chart, hover_styles = { fill: "blue", opacity: 0.5 }){
let styles = hover_styles;
const line_styles = {
stroke: "blue",
"stroke-width": 3
};
// Workaround if it's in a figure
const type = d3.select(chart).node().tagName;
let wrapper =
type === "FIGURE" ? d3.select(chart).select("svg") : d3.select(chart);
// Workaround if there's a legend....
const numSvgs = d3.select(chart).selectAll("svg").size();
if (numSvgs === 2)
wrapper = d3
.select(chart)
.selectAll("svg")
.filter((d, i) => i === 1);
wrapper.style("overflow", "visible"); // to avoid clipping at the edges
// Set pointer events to visibleStroke if the fill is none (e.g., if its a line)
wrapper.selectAll("path").each(function (data, index, nodes) {
// For line charts, set the pointer events to be visible stroke
if (
d3.select(this).attr("fill") === null ||
d3.select(this).attr("fill") === "none"
) {
d3.select(this).style("pointer-events", "visibleStroke");
styles = _.isEqual(hover_styles, { fill: "blue", opacity: 0.5 })
? line_styles
: hover_styles;
}
});
const tip = wrapper
.selectAll(".hover-tip")
.data([""])
.join("g")
.attr("class", "hover")
.style("pointer-events", "none")
.style("text-anchor", "middle");
// Add a unique id to the chart for styling
const id = id_generator();
// Add the event listeners
d3.select(chart)
.classed(id, true) // using a class selector so that it doesn't overwrite the ID
.selectAll("title")
.each(function () {
// Get the text out of the title, set it as an attribute on the parent, and remove it
const title = d3.select(this); // title element that we want to remove
const parent = d3.select(this.parentNode); // visual mark on the screen
const t = title.text();
if (t) {
parent.attr("__title", t).classed("has-title", true);
title.remove();
}
// Mouse events
parent
.on("mousemove", function (event) {
const text = d3.select(this).attr("__title");
const pointer = d3.pointer(event, wrapper.node());
if (text) tip.call(hover, pointer, text.split("\n"));
else tip.selectAll("*").remove();
// Raise it
d3.select(this).raise();
// Keep within the parent horizontally
const tipSize = tip.node().getBBox();
if (pointer[0] + tipSize.x < 0)
tip.attr(
"transform",
`translate(${tipSize.width / 2}, ${pointer[1] + 7})`
);
else if (pointer[0] + tipSize.width / 2 > wrapper.attr("width"))
tip.attr(
"transform",
`translate(${wrapper.attr("width") - tipSize.width / 2}, ${
pointer[1] + 7
})`
);
})
.on("mouseout", function (event) {
tip.selectAll("*").remove();
// Lower it!
d3.select(this).lower();
});
});
// Remove the tip if you tap on the wrapper (for mobile)
wrapper.on("touchstart", () => tip.selectAll("*").remove());
// Add styles
const style_string = Object.keys(styles)
.map((d) => {
return `${d}:${styles[d]};`;
})
.join("");
// Define the styles
const style = html`<style>
.${id} .has-title {
cursor: pointer;
pointer-events: all;
}
.${id} .has-title:hover {
${style_string}
}
</style>`;
chart.appendChild(style);
return chart;
}
function hover(tip, pos, text){
const side_padding = 10;
const vertical_padding = 5;
const vertical_offset = 15;
// Empty it out
tip.selectAll("*").remove();
// Append the text
tip
.style("text-anchor", "middle")
.style("pointer-events", "none")
.attr("transform", `translate(${pos[0]}, ${pos[1] + 7})`)
.selectAll("text")
.data(text)
.join("text")
.style("dominant-baseline", "ideographic")
.text((d) => d)
.attr("y", (d, i) => (i - (text.length - 1)) * 15 - vertical_offset)
.style("font-weight", (d, i) => (i === 0 ? "bold" : "normal"));
const bbox = tip.node().getBBox();
// Add a rectangle (as background)
tip
.append("rect")
.attr("y", bbox.y - vertical_padding)
.attr("x", bbox.x - side_padding)
.attr("width", bbox.width + side_padding * 2)
.attr("height", bbox.height + vertical_padding * 2)
.style("fill", "white")
.style("stroke", "#d3d3d3")
.lower();
}
function id_generator(){
var S4 = function () {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
return "a" + S4() + S4();
}
scatter(iris)
</script>
</html>
I am converting the d3 contour example https://observablehq.com/#d3/volcano-contours?collection=#d3/d3-contour to vanilla js for a stand alone application. I am new to observable and JS.
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="https://d3js.org/d3-contour.v2.min.js"></script>
<script src="https://d3js.org/d3-hsv.v0.1.min.js"></script>
</head>
<body>
<div class="container"></div>
<script>
function vChart(container){
const data = FileAttachment("volcano.json").json();
const height = data.height;
const width = data.width;
const contours = d3.contours().size([width, height]);
const path = d3.geoPath();
function interpolateTerrain() {
const i0 = d3.interpolateHsvLong(d3.hsv(120, 1, 0.65), d3.hsv(60, 1, 0.90));
const i1 = d3.interpolateHsvLong(d3.hsv(60, 1, 0.90), d3.hsv(0, 0, 0.95));
return t => t < 0.5 ? i0(t * 2) : i1((t - 0.5) * 2);
}
const color = d3.scaleSequential(interpolateTerrain).domain(d3.extent(data.values)).nice();
const thresholds = color.ticks(20);
const wide = Generators.observe(notify => {
let wide;
function resized() {
let w = innerWidth > 640;
if (w !== wide) notify(wide = w);
}
resized();
addEventListener("resize", resized);
return () => removeEventListener("resize", resized);
})
const svg = d3.select(container).append('svg')
.attr("viewBox", wide ? [0, 0, width, height] : [0, 0, height, width])
.style("display", "block")
.style("margin", "0 -14px")
.style("width", "calc(100% + 28px)")
.style("height", "auto");
const g = svg.append("g")
.attr("transform", wide ? null : `
rotate(90 ${width/2},${height/2})
translate(${(width - height) / 2},${(width - height) / 2})
`)
.attr("stroke", "white")
.attr("stroke-width", 0.03);
for (const threshold of thresholds) {
g.append("path")
.attr("d", path(contours.contour(data.values, threshold)))
.attr("fill", color(threshold));
yield svg.node();
}
}
vChart('.container')
</script>
</body>
</html>
This results in two errors
Uncaught ReferenceError: Fileattachment is not defined
Uncaught ReferenceError: Generators is not defined
I am not able to recreate the generator function, Fileattachment function I guess it is related to observable.
I have been trying this code to create a bar chart with given data. It works but it never returns a red, rather returns blue always. I have tried putting b[i]>0, still only blue bars. The function wit parameter b is executed for sure and I have tried (b,i) too.
<!DOCTYPE html>
<html>
<head>
<script src = "https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<svg height = "250px" width="500px"></svg>
<script>
var b = [5,9,6,4,3];
var x = 100;
const height = 250;
for(var i=0; i<b.length;i++)
{
var svg = d3.select("svg").data(b).append("rect").attr("x",x)
.attr("y",height - (b[i]*20))
.attr("width",20).attr("height", b[i]*20).attr("fill", function(b){
if(b[i]<6) //This if condition never gets checked and hence doesn't work
{
return "red";
}
else
{
return "blue"; //This executes
}
})
x = x + 25; //Increment for the position of next bar
}
</script>
</body>
</html>
You make a shadow variable b, as an argument of the callback, so it is not an array, but the item of it. Since you are using cycle for drawing each point separately, you could avoid use callback for this.
So instead of
.attr("fill", function(b) { ... })
you need to write this
.attr("fill", b[i] < 6 ? "red" : "blue")
Btw, d3 js can iterate points for you:
<script>
var b = [5, 9, 6, 4, 3];
var xOffset = 100;
const height = 250;
var svg = d3.select("svg")
.selectAll('rect')
.data(b)
.enter()
.append('rect')
.attr("x", (d, i) => xOffset + 25 * i)
.attr("y", d => height - d * 20)
.attr("width", 20)
.attr("height", d => d * 20)
.attr("fill", d => d < 6 ? "red" : "blue");
</script>