{
const svg = d3.select(DOM.svg(400, 600));
const margin = { top: 50, right: 50, bottom: 80, left: 50 };
const width = +svg.attr("width") - margin.left - margin.right;
const height = +svg.attr("height") - margin.top - margin.bottom;
const x = d3
.scaleLinear()
.domain([0, d3.max(dataPricing, (d) => Math.max(d.Brightdata, d.Apify))])
.range([0, width]);
const y = d3
.scaleLog()
.domain([
d3.min(dataPricing, (d) => d["Query Count (per Month)"]),
d3.max(dataPricing, (d) => d["Query Count (per Month)"])
])
.range([height, 0]);
const maxX = d3.max(dataPricing, (d) => Math.max(d.Brightdata, d.Apify));
const tickValuesX = [0, maxX / 2, maxX];
const gX = svg
.append("g")
.attr("transform", `translate(${margin.left},${height + margin.top})`)
.call(d3.axisBottom(x).tickValues(tickValuesX).tickFormat(d3.format(".0s")))
.attr("font-size", "16px")
.attr("font-family", fontFamily)
.append("text")
.attr("class", "label")
.attr("x", width + 20)
.attr("y", 50)
.attr("fill", "#000")
.attr("text-anchor", "end")
.attr("font-size", "16px")
.attr("font-family", fontFamily)
.attr("font-weight", "bold")
.text("Cost ($)");
const gY = svg
.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${margin.left},${margin.top})`)
.call(d3.axisLeft(y))
.attr("font-size", "16px")
.attr("font-family", fontFamily)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(0)")
.attr("y", -20)
.attr("x", -margin.left)
.attr("fill", "#000")
.attr("text-anchor", "start")
.attr("font-size", "16px")
.attr("font-weight", "bold")
.attr("font-family", fontFamily)
.text("Monthly Query Count");
svg
.selectAll(".brightdata-circle")
.data(dataPricing)
.enter()
.append("circle")
.attr("class", "brightdata-circle")
.attr("cx", (d) => x(d.Brightdata) + margin.left)
.attr("cy", (d) => y(d["Query Count (per Month)"]) + margin.top)
.attr("r", 5)
.style("fill", "blue")
.on("mouseover", function () {
svg
.selectAll(".hover-label")
.data(dataPricing)
.enter()
.append("text")
.attr("class", "hover-label")
.attr("x", (d) => x(d.Brightdata) + margin.left + 10)
.attr("y", (d) => y(d["Query Count (per Month)"]) + margin.top - 10)
.attr("font-family", fontFamily)
.attr("font-size", "12px")
.attr("fill", "blue")
.text((d) => d.Brightdata);
})
.on("mouseout", function () {
svg.selectAll(".hover-label").remove();
});
const lineGeneratorBrightdata = d3
.line()
.x((d) => x(d.Brightdata) + margin.left)
.y((d) => y(d["Query Count (per Month)"]) + margin.top)
.curve(d3.curveLinear);
svg
.append("path")
.data([dataPricing])
.attr("d", lineGeneratorBrightdata)
.attr("fill", "none")
.attr("stroke", "blue")
.attr("stroke-width", 2)
.on("mouseover", showLabelsBrighdata)
.on("mouseout", hideLabels);
svg
.selectAll(".apify-circle")
.data(dataPricing)
.enter()
.append("circle")
.attr("class", "apify-circle")
.attr("cx", (d) => x(d.Apify) + margin.left)
.attr("cy", (d) => y(d["Query Count (per Month)"]) + margin.top)
.attr("r", 5)
.style("fill", "green");
const lineGeneratorApify = d3
.line()
.x((d) => x(d.Apify) + margin.left)
.y((d) => y(d["Query Count (per Month)"]) + margin.top)
.curve(d3.curveLinear);
svg
.append("path")
.data([dataPricing])
.attr("d", lineGeneratorApify)
.attr("fill", "none")
.attr("stroke", "green")
.attr("stroke-width", 2)
.on("mouseover", showLabelsApify)
.on("mouseout", hideLabels);
function showLabelsBrighdata() {
svg
.selectAll(".hover-label")
.data(dataPricing)
.enter()
.append("text")
.attr("class", "hover-label")
.attr("x", (d) => x(d.Brightdata) + margin.left + 10)
.attr("y", (d) => y(d["Query Count (per Month)"]) + margin.top - 10)
.attr("font-family", fontFamily)
.attr("font-size", "12px")
.attr("fill", "black")
.text((d) => d.Brightdata);
}
function showLabelsApify() {
svg
.selectAll(".hover-label")
.data(dataPricing)
.enter()
.append("text")
.attr("class", "hover-label")
.attr("x", (d) => x(d.Apify) + margin.left + 10)
.attr("y", (d) => y(d["Query Count (per Month)"]) + margin.top - 10)
.attr("font-family", fontFamily)
.attr("font-size", "12px")
.attr("fill", "green")
.text((d) => d.Apify);
}
function hideLabels() {
svg.selectAll(".hover-label").remove();
}
return svg.node();
}