diff --git a/index.html b/index.html index b623335..c1be752 100644 --- a/index.html +++ b/index.html @@ -21,7 +21,17 @@

City Circuit

-
+
+

+

+

+

Popular Items:

+ +

Best Reviews:

+ +

Worst Reviews:

+ +
diff --git a/script.js b/script.js index fabfd00..e8329d0 100644 --- a/script.js +++ b/script.js @@ -365,7 +365,23 @@ const mockData = { ] }; + function calculateNodeSize(place) { + // This is a simple calculation, you can make it more complex + const popularityFactor = place.reviews / 100; + const ratingFactor = place.rating; + return 5 + (popularityFactor * ratingFactor); +} + function createGraph(data) { + // Clear previous content + d3.select("#graph").html(""); + d3.select("#infoName").text(""); + d3.select("#infoRating").text(""); + d3.select("#infoReviews").text(""); + d3.select("#infoPopular").html(""); + d3.select("#infoBestReviews").html(""); + d3.select("#infoWorstReviews").html(""); + const width = document.getElementById('graph').clientWidth; const height = document.getElementById('graph').clientHeight; @@ -375,34 +391,65 @@ function createGraph(data) { .attr("height", height); const simulation = d3.forceSimulation(data) - .force("charge", d3.forceManyBody().strength(-50)) + .force("charge", d3.forceManyBody().strength(-100)) .force("center", d3.forceCenter(width / 2, height / 2)) - .force("collision", d3.forceCollide().radius(20)); + .force("collision", d3.forceCollide().radius(d => calculateNodeSize(d))); const nodes = svg.selectAll("circle") .data(data) .enter() .append("circle") - .attr("r", d => 10 + d.rating * 2) - .style("fill", d => d.type === "restaurants" ? "red" : "blue"); + .attr("r", d => calculateNodeSize(d)) + .style("fill", d => d.type === "restaurants" ? "#ff9999" : "#99ccff"); + + // Add tooltips + const tooltip = d3.select("body").append("div") + .attr("class", "node-tooltip") + .style("opacity", 0); + + nodes.on("mouseover", (event, d) => { + tooltip.transition() + .duration(200) + .style("opacity", .9); + tooltip.html(`${d.name}
Rating: ${d.rating}
Reviews: ${d.reviews}`) + .style("left", (event.pageX + 10) + "px") + .style("top", (event.pageY - 28) + "px"); + }) + .on("mouseout", () => { + tooltip.transition() + .duration(500) + .style("opacity", 0); + }); + + nodes.on("click", (event, d) => showInfo(d)); simulation.on("tick", () => { nodes .attr("cx", d => d.x) .attr("cy", d => d.y); }); - - nodes.on("click", (event, d) => showInfo(d)); } function showInfo(place) { - const infoPanel = document.getElementById('infoPanel'); - infoPanel.innerHTML = ` -

${place.name}

-

Rating: ${place.rating}

-

Reviews: ${place.reviews}

-

Type: ${place.type}

- `; + d3.select("#infoName").text(place.name); + d3.select("#infoRating").text(`Rating: ${place.rating}`); + d3.select("#infoReviews").text(`Reviews: ${place.reviews}`); + + const popularItems = place.popularItems || place.keyAttractions; + d3.select("#infoPopular").html(""); + popularItems.forEach(item => { + d3.select("#infoPopular").append("li").text(item); + }); + + d3.select("#infoBestReviews").html(""); + place.bestReviews.forEach(review => { + d3.select("#infoBestReviews").append("li").text(review); + }); + + d3.select("#infoWorstReviews").html(""); + place.worstReviews.forEach(review => { + d3.select("#infoWorstReviews").append("li").text(review); + }); } document.getElementById('searchButton').addEventListener('click', () => { @@ -410,4 +457,7 @@ document.getElementById('searchButton').addEventListener('click', () => { const searchInput = document.getElementById('searchInput').value; // For now, we're ignoring the search input and just using mock data createGraph(mockData[placeType]); -}); \ No newline at end of file +}); + +// Initial graph creation +createGraph(mockData.restaurants); \ No newline at end of file diff --git a/styles.css b/styles.css index e969aac..4c57931 100644 --- a/styles.css +++ b/styles.css @@ -1,32 +1,92 @@ body { - font-family: Arial, sans-serif; + font-family: 'Arial', sans-serif; margin: 0; padding: 0; + background-color: #f0f0f0; } header { - background-color: #333; + background-color: #4a90e2; color: white; text-align: center; padding: 1em; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); } nav { padding: 1em; - background-color: #f0f0f0; + background-color: #ffffff; + display: flex; + justify-content: center; + align-items: center; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +select, input, button { + font-size: 1em; + padding: 0.5em; + margin: 0 0.5em; +} + +#searchButton { + background-color: #4a90e2; + color: white; + border: none; + padding: 0.5em 1em; + cursor: pointer; + transition: background-color 0.3s; +} + +#searchButton:hover { + background-color: #3a7bc8; } main { display: flex; + padding: 1em; } #graph { width: 70%; height: 600px; + background-color: #ffffff; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); } #infoPanel { width: 30%; padding: 1em; - background-color: #f9f9f9; + background-color: #ffffff; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + margin-left: 1em; + overflow-y: auto; + max-height: 600px; +} + +#infoPanel h2 { + color: #4a90e2; +} + +#infoPanel h3 { + color: #333; +} + +#infoPanel ul { + padding-left: 1.5em; +} + +#infoPanel li { + margin-bottom: 0.5em; +} + +.node-tooltip { + position: absolute; + background-color: rgba(0, 0, 0, 0.7); + color: white; + padding: 5px; + border-radius: 3px; + font-size: 12px; + pointer-events: none; } \ No newline at end of file