Accepted answer

You just missed 2 minor things:

  1. In the zoom function, the scales to be used would be the new X and Y scales, as you've to transform the circles in the new domain.

    circles.attr('cx', (d) => xNewScale(d.duration))
       .attr('cy', (d) => yNewScale(d.priority));
  2. Selection:

    var circles = svg.selectAll('dot')

would actually return the "titles" as the current selection and so now, the variable circles is a node group of titles whose attributes (cx and cy) get changed in the zoom function which is not what we want as we want to change the attributes of the <circle>s. And so, changing the above to the following:

// Add the scatterplot
var circles = svg.selectAll("dot")
  .attr('fill' ..);

  .html(d => {
    return 'Date : ' + timeFormat(new Date(d.start)) + ',<br> Description: ' + d.description + ',<br> Impact: ' + d.priority + ',<br> Hours: ' + Math.round(d.duration)

Similarly, I've made changes to the red circles (outer).

Comprising all of the above, here's a fork of your code:

Hope this helps.

Related Query

More Query from same tag