diff --git a/treemap/main.js b/treemap/main.js index 43ec57d..bb47325 100644 --- a/treemap/main.js +++ b/treemap/main.js @@ -451,16 +451,21 @@ async function fetchData() { console.log(root.leaves()); + // Create group ID (ocean + newGroup) + const groupIDs = root + .leaves() + .map((d) => d.parent.data[0].replace(/\s+/g, '-') + '_' + d.data[0]); + // Create a group for each node const nodes = svg .selectAll('g') .data(root.leaves()) .enter() .append('g') - .attr('class', (d, i) => { - return root.leaves()[i].parent.data[0]; // Assuming this returns the class name - }) - .attr('transform', (d) => `translate(${d.x0},${d.y0})`); + .attr('transform', (d) => `translate(${d.x0},${d.y0})`) + .attr('id', (d, i) => { + return `${groupIDs[i]}`; + }); // Define colourScale const colourScale = d3 @@ -758,35 +763,35 @@ async function fetchData() { function getDetailedData(ocean) { switch (ocean) { - case 'Pacific': + case 'Pacific Ocean': return { Predator: pPredator, Prey: pPrey, Others: pOthers, }; - case 'Atlantic': + case 'Atlantic Ocean': return { Predator: atPredator, Prey: atPrey, Others: atOthers, }; - case 'Indian': + case 'Indian Ocean': return { Predator: iPredator, Prey: iPrey, Others: iOthers, }; - case 'South': + case 'South Ocean': return { Predator: sPredator, Others: sOthers, }; - case 'North': + case 'North Sea': return { Predator: nPredator, Others: nOthers, }; - case 'Arctic': + case 'Arctic Ocean': return { Predator: arPredator, }; @@ -831,6 +836,66 @@ async function fetchData() { //tree map description disappear when zoom in description.transition().duration(500).style('opacity', 0); + // Aggregate the data for the selected ocean and archetype + const selectedSeaname = d.parent.data[0]; + const selectedNewGroup = d.data[0]; + let rolledupData = getDetailedData(selectedSeaname)[selectedNewGroup]; + rolledupData = Array.from(rolledupData, ([key, value]) => ({ + name: key, + value, + })); + rolledupData = rolledupData.sort((a, b) => b.value - a.value); + + const secondTreemapRoot = d3 + .hierarchy({ children: rolledupData }, (d) => d.children) + .sum((d) => d.value); + + d3.treemap().size([width, height]).padding(3).round(true)( + secondTreemapRoot + ); + + // Create a group for each node + const groupID = `${selectedSeaname.replace( + /\s+/g, + '-' + )}_${selectedNewGroup}`; + const secondTreemap = d3.select(`#${groupID}`); + + if (secondTreemap.empty()) { + secondTreemap = svg.append('g').attr('id', groupID); + } + + secondTreemap + .selectAll('rect') + .data(secondTreemapRoot.leaves(), (d) => d.data.name) + .enter() + .append('rect') + .attr('class', 'detailed-node') + .attr('x', (d) => d.x0) + .attr('y', (d) => d.y0) + .attr('width', (d) => d.x1 - d.x0) + .attr('height', (d) => d.y1 - d.y0) + .attr('fill-opacity', 0.9) + .attr('stroke', 'none') + .attr('id', (d, i) => { + return `${groupID}_${d.data.name}`; + }) + .attr('fill', colourScale(selectedSeaname)); + + secondTreemap + .selectAll('text') + .data(secondTreemapRoot.leaves(), (d) => d.data.name) + .enter() + .append('text') + .text((d) => d.data.name) + .attr('class', 'detailed-node') + .attr('x', (d) => d.x0 + 10) + .attr('y', (d) => d.y0 + 25) + .style('font-family', "'Open Sans', sans-serif") + .style('font-weight', 'regular') + .style('fill', 'white') + .style('font-size', '14px'); + // Secondary Legend, appears when zoomed in and hides when zoom out -------------------------------------------- // Depth const legendDepth = { @@ -1036,103 +1101,6 @@ async function fetchData() { .transition() .duration(1200) .style('opacity', 1); - - // Fetch detailed data and update the treemap - const detailedData = getDetailedData( - 'Pacific', - 'Atlantic', - 'Indian', - 'South', - 'North', - 'Arctic' - ); - console.log('Detailed Data:', detailedData); - - if (Object.keys(detailedData).length > 0) { - const detailedRoot = d3 - .hierarchy({ - children: Object.entries(detailedData).map(([key, value]) => ({ - name: key, - children: Array.from(value, ([depthRange, count]) => ({ - name: getDepthRange(depthRange), - value: count, - })), - })), - }) - .sum((d) => d.value) - .sort((a, b) => b.value - a.value); - - console.log('Detailed Root:', detailedRoot); - - treemapLayout(detailedRoot); - - const detailedNodes = svg.selectAll(".detailed-node") - .data(detailedRoot.leaves()) - .enter() - .append("g") - .attr("class", "detailed-node") - .attr("transform", node => `translate(${node.x0},${node.y0})`); - - - detailedNodes.append("rect") - .attr("width", node => node.x1 - node.x0) - .attr("height", node => node.y1 - node.y0) - .attr("fill", node => { - const parentColor = colourScale(node.parent.data.name); - const shade = d3.scaleLinear() - .domain([0, (detailedRoot.children ? detailedRoot.children.length : 1) - 1]) - .range([0.3, 0.7]); // Make the shade range darker and wider - return d3.color(parentColor).darker(shade(detailedRoot.children ? detailedRoot.children.indexOf(node) : 1)); - }) - .attr("fill-opacity", 1) - .attr("stroke", "none"); - - detailedNodes.append("text") - .attr("x", 10) - .attr("y", 25) - .style("font-family", "'Open Sans', sans-serif") - .style("font-weight", "regular") - .style("fill", "white") - .style("font-size", node => { - const fontSize = Math.min((node.x1 - node.x0) / 5, (node.y1 - node.y0) / 5, 16); - return fontSize < 10 ? "0px" : `${fontSize}px`; - }) - .text(node => getDepthRange(node.data.value)) - .each(function(node) { - const bbox = this.getBBox(); - if (bbox.width > (node.x1 - node.x0) || bbox.height > (node.y1 - node.y0)) { - d3.select(this).remove(); - } - }); - - // Add fade-in and scale animation for the detailed nodes - setTimeout(() => { - detailedNodes.style("opacity", 0) - .attr("transform", node => `translate(${x(node.x0)},${y(node.y0)}) scale(0.1)`) - .transition() - .duration(1500) - .style("opacity", 0.9) - .attr("transform", node => `translate(${x(node.x0)},${y(node.y0)}) scale(1)`); - }, 2000); - - detailedNodes.append("text") - .attr("x", 10) - .attr("y", 25) - .style("font-family", "'Open Sans', sans-serif") - .style("font-weight", "regular") - .style("fill", "white") - .style("font-size", node => { - const fontSize = Math.min((x(node.x1) - x(node.x0)) / 5, (y(node.y1) - y(node.y0)) / 5, 16); - return fontSize < 10 ? "0px" : `${fontSize}px`; - }) - .text(node => getDepthRange(node.data.name)) - .each(function(node) { - const bbox = this.getBBox(); - if (bbox.width > (x(node.x1) - x(node.x0)) || bbox.height > (y(node.y1) - y(node.y0))) { - d3.select(this).remove(); - } - }); - } } nodes.on('click', function (event, d) { @@ -1240,13 +1208,13 @@ async function fetchData() { .html( //find a way to make it flexible ` - - Fish Thumbnail -
${mergedData.common_name} -
${mergedData.title} -
Archetype: ${mergedData.newGroup} -
Depth: ${mergedData.depth} m -

Map + + Fish Thumbnail +
${fishData.common_name} +
${fishData.title} +
Archetype: ${fishData.newGroup} +
Depth: ${fishData.depth} m +

Map ` ); }) @@ -1353,7 +1321,7 @@ async function fetchData() { .style('text-align', 'center') .style('padding-top', '50px') .text( - 'Major Studio I | Exercise 2: Qualitative Representation | Tak | Bella | Xuan' + 'Major Studio I | Exercise 2: Qualitative Representation | Hyeonjeong | Xuan' ); } catch (error) { console.error('Error fetching or processing data:', error);