imad-hl commented on code in PR #35859:
URL: https://github.com/apache/superset/pull/35859#discussion_r2473983989


##########
superset-frontend/plugins/legacy-plugin-chart-country-map/src/CountryMap.js:
##########
@@ -83,112 +106,200 @@ function CountryMap(element, props) {
     .attr('width', width)
     .attr('height', height)
     .attr('preserveAspectRatio', 'xMidYMid meet');
-  const backgroundRect = svg
-    .append('rect')
-    .attr('class', 'background')
-    .attr('width', width)
-    .attr('height', height);
+
   const g = svg.append('g');
   const mapLayer = g.append('g').classed('map-layer', true);
-  const textLayer = g
+  const textLayer = svg
     .append('g')
-    .classed('text-layer', true)
+    .attr('class', 'text-layer')
     .attr('transform', `translate(${width / 2}, 45)`);
-  const bigText = textLayer.append('text').classed('big-text', true);
+  const bigText = textLayer
+    .append('text')
+    .classed('big-text', true)
+    .style('font-size', '18px');
   const resultText = textLayer
     .append('text')
     .classed('result-text', true)
-    .attr('dy', '1em');
-
-  let centered;
-
-  const clicked = function clicked(d) {
-    const hasCenter = d && centered !== d;
-    let x;
-    let y;
-    let k;
-    const halfWidth = width / 2;
-    const halfHeight = height / 2;
-
-    if (hasCenter) {
-      const centroid = path.centroid(d);
-      [x, y] = centroid;
-      k = 4;
-      centered = d;
-    } else {
-      x = halfWidth;
-      y = halfHeight;
-      k = 1;
-      centered = null;
-    }
+    .attr('dy', '1em')
+    .style('font-size', '26px');
+
+  // Cross-filter support
+  const getCrossFilterDataMask = source => {
+    const selected = filterState.selectedValues || [];
+    const iso = source?.properties?.ISO;
+    if (!iso) return undefined;
 
-    g.transition()
-      .duration(750)
-      .attr(
-        'transform',
-        
`translate(${halfWidth},${halfHeight})scale(${k})translate(${-x},${-y})`,
-      );
-    textLayer
-      .style('opacity', 0)
-      .attr(
-        'transform',
-        `translate(0,0)translate(${x},${hasCenter ? y - 5 : 45})`,
-      )
-      .transition()
-      .duration(750)
-      .style('opacity', 1);
-    bigText
-      .transition()
-      .duration(750)
-      .style('font-size', hasCenter ? 6 : 16);
-    resultText
-      .transition()
-      .duration(750)
-      .style('font-size', hasCenter ? 16 : 24);
+    const isSelected = selected.includes(iso);
+    const values = isSelected ? [] : [iso];
+
+    return {
+      dataMask: {
+        extraFormData: {
+          filters: values.length
+            ? [{ col: entity, op: 'IN', val: values }]
+            : [],
+        },
+        filterState: {
+          value: values.length ? values : null,
+          selectedValues: values.length ? values : null,
+        },
+      },
+      isCurrentValueSelected: isSelected,
+    };
   };
 
-  backgroundRect.on('click', clicked);
+  // Handle right-click context menu
+  const handleContextMenu = feature => {
+    const pointerEvent = d3.event;
+
+    // Only prevent default if we have a context menu handler
+    if (typeof onContextMenu === 'function') {
+      pointerEvent?.preventDefault();
+    }
+
+    const iso = feature?.properties?.ISO;
+    if (!iso || typeof onContextMenu !== 'function') return;
+
+    const drillVal = iso;
+    const drillToDetailFilters = [
+      { col: entity, op: '==', val: drillVal, formattedVal: drillVal },
+    ];
+    const drillByFilters = [{ col: entity, op: '==', val: drillVal }];
 
-  const selectAndDisplayNameOfRegion = function selectAndDisplayNameOfRegion(
-    feature,
-  ) {
+    onContextMenu(pointerEvent.clientX, pointerEvent.clientY, {
+      drillToDetail: drillToDetailFilters,
+      crossFilter: getCrossFilterDataMask(feature),
+      drillBy: { filters: drillByFilters, groupbyFieldName: 'entity' },
+    });
+  };
+
+  const selectAndDisplayNameOfRegion = feature => {
     let name = '';
-    if (feature && feature.properties) {
-      if (feature.properties.ID_2) {
-        name = feature.properties.NAME_2;
-      } else {
-        name = feature.properties.NAME_1;
-      }
+    if (feature?.properties) {
+      name = feature.properties.NAME_2 || feature.properties.NAME_1 || '';
     }
     bigText.text(name);
   };
 
-  const updateMetrics = function updateMetrics(region) {
-    if (region.length > 0) {
-      resultText.text(format(region[0].metric));
-    }
+  const updateMetrics = regionRows => {
+    if (regionRows?.length > 0) resultText.text(format(regionRows[0].metric));
+    else resultText.text('');
   };
 
-  const mouseenter = function mouseenter(d) {
-    // Darken color
+  const mouseenter = function (d) {
     let c = colorFn(d);
-    if (c !== 'none') {
-      c = d3.rgb(c).darker().toString();
-    }
+    if (c && c !== 'none') c = d3.rgb(c).darker().toString();
     d3.select(this).style('fill', c);
     selectAndDisplayNameOfRegion(d);
-    const result = data.filter(
-      region => region.country_id === d.properties.ISO,
-    );
+    const result = data.filter(r => r.country_id === d?.properties?.ISO);
     updateMetrics(result);
   };
 
-  const mouseout = function mouseout() {
-    d3.select(this).style('fill', colorFn);
+  const mouseout = function () {
+    d3.select(this).style('fill', d => colorFn(d));
     bigText.text('');
     resultText.text('');
   };
 
+  // Zoom with panning bounds
+  const zoom = d3.behavior
+    .zoom()
+    .scaleExtent([1, 4])
+    .on('zoom', () => {
+      const { translate, scale } = d3.event; // [tx, ty]
+      let [tx, ty] = translate;
+
+      const scaledW = width * scale;
+      const scaledH = height * scale;
+      const minX = Math.min(0, width - scaledW);
+      const maxX = 0;
+      const minY = Math.min(0, height - scaledH);
+      const maxY = 0;
+
+      // clamp
+      tx = Math.max(Math.min(tx, maxX), minX);
+      ty = Math.max(Math.min(ty, maxY), minY);
+
+      g.attr('transform', `translate(${tx}, ${ty}) scale(${scale})`);
+      zoomStates[chartKey] = { scale, translate: [tx, ty] };
+    });

Review Comment:
   I tried using 'zoomend' and throttling to improve performance, but it made 
the zoom reset after clicks. 
   
   so in 9651b63 :  I decided to keep the original zoom handler and simply 
update the WeakMap when the transform actually changes, which keeps zoom smooth 
and avoids memory issues.
   
   ( See Lines 223 -> 234 in CountryMap.js 
   
    
https://github.com/imad-hl/superset/blob/d818e4a41a0b1abaa92e32a2381ece98c781b00d/superset-frontend/plugins/legacy-plugin-chart-country-map/src/CountryMap.js#L223
   
   
https://github.com/imad-hl/superset/blob/d818e4a41a0b1abaa92e32a2381ece98c781b00d/superset-frontend/plugins/legacy-plugin-chart-country-map/src/CountryMap.js#L234
   )



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to