Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to change the initial custom styling of a feature after we draw it? #1298

Open
alamenai opened this issue Oct 1, 2024 · 8 comments
Open

Comments

@alamenai
Copy link

alamenai commented Oct 1, 2024

Hi everyone,

In the image below I draw roofs on the the top of the building:

image

This how I draw the roof :

  const createRoofPolygonFeature = (roofSurface: RoofSurface): Feature => {
    const polygon = turf.polygon([roofSurface.coords])
    const roofCoordinates = polygon.geometry.coordinates

    if (roofSurface.holes) {
      roofSurface.holes.forEach((hole: Position[]) => {
        roofCoordinates.push(hole)
      })
    }

    const feature = {
      type: "Feature",
      properties: {
        id: roofSurface.id,
        user_color: "#16a34a", // Default color with 'user_' prefix
      },
      geometry: {
        type: "Polygon",
        coordinates: roofCoordinates,
      },
    }

    // Store the draw instance in the mapRef
    if (mapRef.current) {
      const current = mapRef.current as MapWithDraw
      current.draw.add(feature as Feature)

      // // Add a new layer for the holes
      // if (roofSurface.holes && roofSurface.holes.length > 0) {
      //   roofSurface.holes.forEach((hole, index) => {
      //     const holeFeature = {
      //       type: "Feature",
      //       properties: {},
      //       geometry: {
      //         type: "Polygon",
      //         coordinates: [hole],
      //       },
      //     }

      //     const holeId = `hole-${roofSurface.id}-${index}`

      //     current.addSource(holeId, {
      //       type: "geojson",
      //       data: holeFeature,
      //     })

      //     current.addLayer({
      //       id: holeId,
      //       type: "fill",
      //       source: holeId,
      //       paint: {
      //         "fill-color": "red",
      //         "fill-opacity": 0.3,
      //       },
      //     })
      //   })
      // }
    }

    return feature as Feature
  }

I created a map instance :

  const createDrawInstance = (modes: { [key: string]: DrawCustomMode }, styles: any): MapboxDraw => {
    return new MapboxDraw({
      displayControlsDefault: false,
      touchEnabled: true,
      modes,
      styles,
      boxSelect: true,
      userProperties: true,
    })
  }

I defined the styles using this function:

  const createDrawStyles = () => {
    return [
      // ACTIVE (being drawn)
      // line stroke
      {
        id: "gl-draw-line",
        type: "line",
        filter: ["all", ["==", "$type", "LineString"], ["!=", "mode", "static"]],
        layout: {
          "line-cap": "round",
          "line-join": "round",
        },
        paint: {
          "line-color": ["get", "color"],
          "line-width": 2,
        },
      },
      // polygon fill
      {
        id: "gl-draw-polygon-fill",
        type: "fill",
        filter: ["all", ["==", "$type", "Polygon"], ["!=", "mode", "static"]],
        paint: {
          "fill-color": "#84cc16",
          "fill-outline-color": "#84cc16",
          "fill-opacity": 0.1, // Semi-opaque fill
        },
      },

      // vertex point halos
      {
        id: "gl-draw-polygon-and-line-vertex-halo-active",
        type: "circle",
        filter: ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
        paint: {
          "circle-radius": 10,
          "circle-color": "#FFF", // White color for vertex halo
        },
      },
      // vertex points
      {
        id: "gl-draw-polygon-and-line-vertex-active",
        type: "circle",
        filter: ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
        paint: {
          "circle-radius": 8,
          "circle-color": "#84cc16", // Red color for vertex points
        },
      },
      // Inactive polygon fill
      {
        id: "gl-draw-polygon-fill-static",
        type: "fill",
        filter: ["all", ["==", "$type", "Polygon"], ["==", "mode", "static"]],
        paint: {
          "fill-color": "#3b82f6", // Blue color for inactive polygon fill
          "fill-outline-color": "#3b82f6", // Blue outline
          "fill-opacity": 0.1, // Semi-opaque fill
        },
      },
      // Inactive polygon outline stroke
      {
        id: "gl-draw-polygon-stroke-static",
        type: "line",
        filter: ["all", ["==", "$type", "Polygon"], ["==", "mode", "static"]],
        layout: {
          "line-cap": "round",
          "line-join": "round",
        },
        paint: {
          "line-color": "#16a34a", // inactive polygon outline
          "line-width": 3, // Line width
        },
      },
      // Inactive vertex points
      {
        id: "gl-draw-polygon-and-line-vertex-static",
        type: "circle",
        filter: ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["==", "mode", "static"]],
        paint: {
          "circle-radius": 3,
          "circle-color": "#3BB2D0", // Blue color for inactive vertex points
        },
      },
      // polygon outline stroke
      // This doesn't style the first edge of the polygon, which uses the line stroke styling instead
      {
        id: "gl-draw-polygon-stroke-active",
        type: "line",
        filter: ["all", ["==", "$type", "Polygon"], ["!=", "mode", "static"]],
        paint: {
          "line-color": ["get", "color"],
          "line-width": 2,
        },
      },
    ]
  }

Everything works as expected but when I click on the roof ID ( circle ID), I want to change the color of that selected roof (feature) to red but Mapbox gl does not influence the change:

c0c91e36-12f5-43ea-8ed6-f3ce538f93c3.webm

This is the method I use:

 // Update roof line color
    if (mapRef.current) {
      const current = mapRef.current as MapWithDraw
      const feature = current.draw.get(roofSurface.id as string) as Feature
      if (feature) {
        feature.properties = {
          ...feature.properties,
          user_color: selectStatus ? "#16a34a" : "#ef4444", // Green when selected, red when deselected
        }
        current.draw.add(feature)
      }
    }

I did not understand how to use the property userProperties Is it possible to change the color of each feature?

I appreciate any example that you can provide.

Example: drawing to polygons in the first rendering and when I click on one of them, it will change its color.

Thank you

@Quietly-20201113
Copy link

I also want to achieve the color change problem, but I change it when drawing a new line

@Quietly-20201113
Copy link

Hi everyone,

In the image below I draw roofs on the the top of the building:

image

This how I draw the roof :

  const createRoofPolygonFeature = (roofSurface: RoofSurface): Feature => {
    const polygon = turf.polygon([roofSurface.coords])
    const roofCoordinates = polygon.geometry.coordinates

    if (roofSurface.holes) {
      roofSurface.holes.forEach((hole: Position[]) => {
        roofCoordinates.push(hole)
      })
    }

    const feature = {
      type: "Feature",
      properties: {
        id: roofSurface.id,
        user_color: "#16a34a", // Default color with 'user_' prefix
      },
      geometry: {
        type: "Polygon",
        coordinates: roofCoordinates,
      },
    }

    // Store the draw instance in the mapRef
    if (mapRef.current) {
      const current = mapRef.current as MapWithDraw
      current.draw.add(feature as Feature)

      // // Add a new layer for the holes
      // if (roofSurface.holes && roofSurface.holes.length > 0) {
      //   roofSurface.holes.forEach((hole, index) => {
      //     const holeFeature = {
      //       type: "Feature",
      //       properties: {},
      //       geometry: {
      //         type: "Polygon",
      //         coordinates: [hole],
      //       },
      //     }

      //     const holeId = `hole-${roofSurface.id}-${index}`

      //     current.addSource(holeId, {
      //       type: "geojson",
      //       data: holeFeature,
      //     })

      //     current.addLayer({
      //       id: holeId,
      //       type: "fill",
      //       source: holeId,
      //       paint: {
      //         "fill-color": "red",
      //         "fill-opacity": 0.3,
      //       },
      //     })
      //   })
      // }
    }

    return feature as Feature
  }

I created a map instance :

  const createDrawInstance = (modes: { [key: string]: DrawCustomMode }, styles: any): MapboxDraw => {
    return new MapboxDraw({
      displayControlsDefault: false,
      touchEnabled: true,
      modes,
      styles,
      boxSelect: true,
      userProperties: true,
    })
  }

I defined the styles using this function:

  const createDrawStyles = () => {
    return [
      // ACTIVE (being drawn)
      // line stroke
      {
        id: "gl-draw-line",
        type: "line",
        filter: ["all", ["==", "$type", "LineString"], ["!=", "mode", "static"]],
        layout: {
          "line-cap": "round",
          "line-join": "round",
        },
        paint: {
          "line-color": ["get", "color"],
          "line-width": 2,
        },
      },
      // polygon fill
      {
        id: "gl-draw-polygon-fill",
        type: "fill",
        filter: ["all", ["==", "$type", "Polygon"], ["!=", "mode", "static"]],
        paint: {
          "fill-color": "#84cc16",
          "fill-outline-color": "#84cc16",
          "fill-opacity": 0.1, // Semi-opaque fill
        },
      },

      // vertex point halos
      {
        id: "gl-draw-polygon-and-line-vertex-halo-active",
        type: "circle",
        filter: ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
        paint: {
          "circle-radius": 10,
          "circle-color": "#FFF", // White color for vertex halo
        },
      },
      // vertex points
      {
        id: "gl-draw-polygon-and-line-vertex-active",
        type: "circle",
        filter: ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["!=", "mode", "static"]],
        paint: {
          "circle-radius": 8,
          "circle-color": "#84cc16", // Red color for vertex points
        },
      },
      // Inactive polygon fill
      {
        id: "gl-draw-polygon-fill-static",
        type: "fill",
        filter: ["all", ["==", "$type", "Polygon"], ["==", "mode", "static"]],
        paint: {
          "fill-color": "#3b82f6", // Blue color for inactive polygon fill
          "fill-outline-color": "#3b82f6", // Blue outline
          "fill-opacity": 0.1, // Semi-opaque fill
        },
      },
      // Inactive polygon outline stroke
      {
        id: "gl-draw-polygon-stroke-static",
        type: "line",
        filter: ["all", ["==", "$type", "Polygon"], ["==", "mode", "static"]],
        layout: {
          "line-cap": "round",
          "line-join": "round",
        },
        paint: {
          "line-color": "#16a34a", // inactive polygon outline
          "line-width": 3, // Line width
        },
      },
      // Inactive vertex points
      {
        id: "gl-draw-polygon-and-line-vertex-static",
        type: "circle",
        filter: ["all", ["==", "meta", "vertex"], ["==", "$type", "Point"], ["==", "mode", "static"]],
        paint: {
          "circle-radius": 3,
          "circle-color": "#3BB2D0", // Blue color for inactive vertex points
        },
      },
      // polygon outline stroke
      // This doesn't style the first edge of the polygon, which uses the line stroke styling instead
      {
        id: "gl-draw-polygon-stroke-active",
        type: "line",
        filter: ["all", ["==", "$type", "Polygon"], ["!=", "mode", "static"]],
        paint: {
          "line-color": ["get", "color"],
          "line-width": 2,
        },
      },
    ]
  }

Everything works as expected but when I click on the roof ID ( circle ID), I want to change the color of that selected roof (feature) to red but Mapbox gl does not influence the change:

c0c91e36-12f5-43ea-8ed6-f3ce538f93c3.webm
This is the method I use:

 // Update roof line color
    if (mapRef.current) {
      const current = mapRef.current as MapWithDraw
      const feature = current.draw.get(roofSurface.id as string) as Feature
      if (feature) {
        feature.properties = {
          ...feature.properties,
          user_color: selectStatus ? "#16a34a" : "#ef4444", // Green when selected, red when deselected
        }
        current.draw.add(feature)
      }
    }

I did not understand how to use the property userProperties Is it possible to change the color of each feature?

I appreciate any example that you can provide.

Example: drawing to polygons in the first rendering and when I click on one of them, it will change its color.

Thank you

I also have a requirement, which is to add serial numbers to the drawing points, such as 123 in your video. I would like to ask whether you use external labels to implement it or implement it in draw. If you implement it in the draw plug-in, how to implement it?

@Quietly-20201113
Copy link

I found the following solution

sameerabit answer
Dynamic color change You can refer to

@Quietly-20201113
Copy link

image


Solved. If you need any help, you can ask me or I will write a blog when I have free time.

@alamenai
Copy link
Author

alamenai commented Nov 1, 2024

Hi @Quietly-20201113, could you share tips on what should I apply in my case?

@Quietly-20201113
Copy link

Hi @Quietly-20201113, could you share tips on what should I apply in my case?


I wrote it when I studied adding serial numbers and other functions. Unfortunately, this function is not what I need, so I did not record it. I can only provide you with the corresponding documentation and examples of API and JSFIDDLE.NET. To you.

[API-UserProperties] (https://github.com/mapbox/mapbox-gl-blob/min/docs/api.md), UserProperties settings are important


[corresponding questions in stackoverflow] https://stackoverflow.com/questions/51303181/How-to-COLOR-InDividual-drawn-with-Mapbox-Gl-Draw)


[Example in JSFIDDLE.NET] (https://jsfiddle.net/5lotf4ka/)


This problem is actually very easy to solve. The biggest problem that hinders our realization is that API's words are difficult to do.

@alamenai
Copy link
Author

alamenai commented Nov 5, 2024

Hi @Quietly-20201113 , the JSFiffle is not found:

image

@Quietly-20201113
Copy link

Hi @Quietly-20201113 , the JSFiffle is not found:

image


Sorry, I may have changed the case of the URL when I copied it, https://jsfiddle.net/5Lotf4ka/, note that the L is capitalized

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@alamenai @Quietly-20201113 and others