Okay please revise my entire code such that each circle has a trail of a faint shadow circle of the same color behind it as it animates. At the end of the animation, all the shadow circles should disappear and loop again just like the main circle. 

/\*
\* main.js
\* Mastering Data Visualization with D3.js
\* Project 2 - Gapminder Clone
\*/

const MARGIN = { LEFT: 100, RIGHT: 10, TOP: 10, BOTTOM: 100 }
const WIDTH = 800 - MARGIN.LEFT - MARGIN.RIGHT
const HEIGHT = 500 - MARGIN.TOP - MARGIN.BOTTOM

const svg = d3.select("#chart-area").append("svg")
 .attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT)
 .attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM)

// Create a tooltip object
const tip = d3.tip()
 .attr("class", "d3-tip")
 .offset([-10, 0])
 .html(d => {
 return `Income: $${d.income}  
Life Expectancy: ${d.life\_exp} years`;
 });
const g = svg.append("g")
 .attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)

let time = 0

// Scales
const x = d3.scaleLinear()
 .range([0, WIDTH])
 .domain([30000, 80000])

const y = d3.scaleLinear()
 .range([HEIGHT, 0])
 .domain([60, 90])

// Labels
const xLabel = g.append("text")
 .attr("y", HEIGHT + 50)
 .attr("x", WIDTH / 2)
 .attr("font-size", "20px")
 .attr("text-anchor", "middle")
 .text("Median Family Income ($)")
const yLabel = g.append("text")
 .attr("transform", "rotate(-90)")
 .attr("y", -40)
 .attr("x", -170)
 .attr("font-size", "20px")
 .attr("text-anchor", "middle")
 .text("Life Expectancy (Years)")
const timeLabel = g.append("text")
 .attr("y", HEIGHT - 15)
 .attr("x", WIDTH - 45)
 .attr("font-size", "40px")
 .attr("opacity", "1")
 .attr("text-anchor", "middle")
 .style("color","#B21112")
 .text("1980")

// X Axis
const xAxisCall = d3.axisBottom(x)
 .tickValues(d3.range(30000, 80000, 10000))
 .tickSize(10)
 .tickFormat(d3.format("$"));
g.append("g")
 .attr("class", "xaxis")
 .attr("transform", `translate(0, ${HEIGHT})`)
 .call(xAxisCall)
 .selectAll(".tick text")
 .style("font-size", "12px");

// Y Axis
const yAxisCall = d3.axisLeft(y)
 .tickValues([60,65,70,75,80,85,90])
 .tickSize(10)
g.append("g")
 .attr("class", "yaxis")
 .call(yAxisCall)
 .selectAll(".tick text")
 .style("font-size", "12px");

// Invoke the tooltip on the SVG container
g.call(tip);
const xGridlines = d3.axisBottom(x)
 .tickValues([30000,40000,50000,60000,70000,80000])
 .tickSize(-HEIGHT)
 .tickFormat("")

const yGridlines = d3.axisLeft(y)
 .tickValues([60,65,70,75,80,85,90])
 .tickSize(-WIDTH)
 .tickFormat("")

g.append("g")
 .attr("class", "grid")
 .attr("transform", `translate(0, ${HEIGHT})`)
 .call(xGridlines)

g.append("g")
 .attr("class", "grid")
 .call(yGridlines)

// add legends 

const legend = g.append("g")
 .attr("transform", `translate(0, ${HEIGHT + 50})`);

legend.append("rect")
 .attr("x", 0)
 .attr("y", 0)
 .attr("width", 10)
 .attr("height",10) 
 .attr("fill", "#003A63")
legend.append("text")
 .attr("x", 20)
 .attr("y", 10)
 .text(" African Americans")

legend.append("rect")
 .attr("x", 0)
 .attr("y", 20)
 .attr("width", 10)
 .attr("height",10)
 .attr("fill", "#C79316")
legend.append("text")
 .attr("x", 20)
 .attr("y", 30)
 .text(" White Americans")

legend.append("rect")
 .attr("x", 0)
 .attr("y", 40)
 .attr("width", 10)
 .attr("height",10)
 .attr("fill", "#B21112")
legend.append("text")
 .attr("x", 20)
 .attr("y", 50)
 .text("All races")

d3.json("data/current\_data.json").then(function(data){
 // clean data
 const formattedData = data.map(year => {
 return year["races"].filter(race => {
 const dataExists = (race.income && race.life\_exp)
 return dataExists
 }).map(race => {
 race.income = Number(race.income)
 race.life\_exp = Number(race.life\_exp)
 return race
 })
 })

 // run the code every 0.1 second
 d3.interval(function(){
 time = (time < formattedData.length-1) ? time + 1 : 0 
 update(formattedData[time])
 timeLabel.text(String(time + 1980))
}, 150)

 // first run of the visualization
 update(formattedData[0])
})

function update(data) {
 // standard transition time for the visualization
 const t = d3.transition()
 .duration(500)
 .ease(d3.easeLinear)

 

 // JOIN new data with old elements.
 const circles = g.selectAll("circle")
 .data(data, d => d.race)

 // EXIT old elements not present in new data.
 circles.exit().remove()

 // ENTER new elements present in new data.
 circles.enter().append("circle")
 .attr("class","circle")
 .attr("fill", d => {
 if (d.race === "white") {
 return "#C79316";
 } else if (d.race === "black") {
 return "#003A63";
 } else if (d.race === "all") {
 return "#B21112";}
})
 .on("mouseover", tip.show)
 .on("mouseout", tip.hide)
 .merge(circles)
 .transition(t)
 .attr("cy", d => y(d.life\_exp))
 .attr("cx", d => x(d.income))
 .attr("r", 25)

 // update the time label
 timeLabel.text(String(time + 1980))
 }
각 원이 움직일 때 그 뒤에 같은 색의 희미한 그림자 원 흔적이 남도록 전체 코드를 수정해 주세요. 애니메이션이 끝나면 모든 그림자 원이 사라지고 메인 원처럼 다시 반복되어야 합니다. /\*\* main.js\* D3.js로 데이터 시각화 마스터하기\* 프로젝트 2 - 갭마인더 클론\*/const MARGIN = { LEFT: 100, RIGHT: 10, TOP: 10, BOTTOM: 100 }const WIDTH = 800 - MARGIN.LEFT - MARGIN.RIGHTconst HEIGHT = 500 - MARGIN.TOP - MARGIN.BOTTOMconst svg = d3.select("#chart-area").append("svg") .attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT) .attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM)// 툴팁 객체 생성const tip = d3.tip() .attr("class", "d3-tip") .offset([-10, 0]) .html(d => { return `소득: $${d.income}  기대수명: ${d.life\_exp} 년`; });const g = svg.append("g") .attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`)let time = 0// 스케일const x = d3.scaleLinear() .range([0, WIDTH]) .domain([30000, 80000])const y = d3.scaleLinear() .range([HEIGHT, 0]) .domain([60, 90])// 라벨const xLabel = g.append("text") .attr("y", HEIGHT + 50) .attr("x", WIDTH / 2) .attr("font-size", "20px") .attr("텍스트-앵커", "가운데") .text("중위 가족 소득 ($)")const yLabel = g.append("text") .attr("transform", "rotate(-90)") .attr("y", -40) .attr("x", -170) .attr("font-size", "20px") .attr("텍스트-앵커", "가운데") .text("기대수명(년)")const timeLabel = g.append("text") .attr("y", HEIGHT - 15) .attr("x", WIDTH - 45) .attr("font-size", "40px") .attr("불투명도", "1") .attr("텍스트-앵커", "가운데") .style("color","#B21112") .text("1980")// X 축const xAxisCall = d3.axisBottom(x) .tickValues(d3.range(30000, 80000, 10000)) .tickSize(10) .tickFormat(d3.format("$"));g.append("g") .attr("class", "x축") .attr("transform", `translate(0, ${HEIGHT})`) .call(xAxisCall) .selectAll(".tick text") .style("font-size", "12px");// Y 축const yAxisCall = d3.axisLeft(y) .tickValues([60,65,70,75,80,85,90]) .tickSize(10)g.append("g") .attr("class", "yaxis") .call(yAxisCall) .selectAll(".tick text") .style("font-size", "12px");// SVG 컨테이너에서 툴팁을 호출합니다.g.call(tip);const xGridlines = d3.axisBottom(x) .tickValues([30000,40000,50000,60000,70000,80000]) .tickSize(-HEIGHT) .tickFormat("")const yGridlines = d3.axisLeft(y) .tickValues([60,65,70,75,80,85,90]) .tickSize(-WIDTH) .tickFormat("")g.append("g") .attr("class", "grid") .attr("transform", `translate(0, ${HEIGHT})`) .call(xGridlines)g.append("g") .attr("class", "grid") .call(y그리드라인)// 범례 추가 const legend = g.append("g") .attr("transform", `translate(0, ${HEIGHT + 50})`);legend.append("rect") .attr("x", 0) .attr("y", 0) .attr("width", 10) .attr("높이",10)  .attr("fill", "#003A63")legend.append("text") .attr("x", 20) .attr("y", 10) .text(" 아프리카계 미국인")legend.append("rect") .attr("x", 0) .attr("y", 20) .attr("width", 10) .attr("높이",10) .attr("fill", "#C79316")legend.append("text") .attr("x", 20) .attr("y", 30) .text(" 백인 미국인")legend.append("rect") .attr("x", 0) .attr("y", 40) .attr("width", 10) .attr("높이",10) .attr("fill", "#B21112")legend.append("text") .attr("x", 20) .attr("y", 50) .text("모든 인종")d3.json("data/current\_data.json").then(function(data){ // 데이터 정리 const formattedData = data.map(year => { return year["races"].filter(race => { const dataExists = (race.income && race.life\_exp) return dataExists }).map(race => { race.income = Number(race.income) race.life\_exp = Number(race.life\_exp) 반환 race }) }) // 0.1초마다 코드 실행 d3.interval(function(){ time = (time < formattedData.length-1) ? time + 1 : 0  update(formattedData[time]) timeLabel.text(String(time + 1980))}, 150) // 시각화 첫 번째 실행 update(formattedData[0])})함수 update(data) { // 시각화의 표준 전환 시간 const t = d3.transition() .duration(500) .ease(d3.easeLinear)  // 새 데이터와 이전 요소를 조인합니다. const circles = g.selectAll("circle") .data(data, d => d.race) // 새 데이터에 존재하지 않는 이전 요소를 EXIT합니다. circles.exit().remove() // 새 데이터에 존재하는 새 요소를 입력합니다. circles.enter().append("circle") .attr("class","circle") .attr("fill", d => { if (d.race === "white") { 반환 "#C79316"; } else if (d.race === "black") { return "#003A63"; } else if (d.race === "all") { return "#B21112";}}) .on("마우스오버", tip.show) .on("마우스아웃", tip.hide) .merge(circles) .transition(t) .attr("cy", d => y(d.life\_exp)) .attr("cx", d => x(d.income)) .attr("r", 25) // 시간 라벨 업데이트 timeLabel.text(String(time + 1980)) }