6

I am trying to improve callout lines on maps I'm making. I'm currently using the method in this link to make my callout lines. That works fine, bu I'd like the lines to always go to the closest point of the label like this:

enter image description hereenter image description here

enter image description hereenter image description here

I think it would work if I used code down the line of this in the expression editor for the geometry generator.

make_line(
  make_point($x, $y),
    make_point((CASE
      WHEN "auxiliary_storage_labeling_positionx" > $x
        THEN "auxiliary_storage_labeling_positionx"
      WHEN ("auxiliary_storage_labeling_positionx"  + "labelwidth") > $x  
            AND ("auxiliary_storage_labeling_positionx") < $x
        THEN ("auxiliary_storage_labeling_positionx" + "labelwidth")
      ELSE $x
      END )
    ,(CASE
      WHEN "auxiliary_storage_labeling_positiony" < $y
        THEN "auxiliary_storage_labeling_positiony"
      WHEN ("auxiliary_storage_labeling_positiony"  + "labelHeight") < $y
            AND ("auxiliary_storage_labeling_positiony") > $y
        THEN ("auxiliary_storage_labeling_positiony"  + "labelHeight")
      ELSE $y
      END )
  )
)

I'm not sure if I have all the < and > correct but that's beside the point. The issue with that is that I can't seem to figure out how to get the width and the height of the label.

I am not very good with the expression editor, and have never done anything with the function editor.

3

you can also use the data defined 'Alignment' to achieve it and use only a simple line within the geometry generator without any AND conditions:

make_line($geometry,make_point( 
"auxiliary_storage_labeling_positionx" , 
"auxiliary_storage_labeling_positiony" ))

enter image description here

and an expression like this for the horizontal:

if(x(closest_point($geometry,
 make_point( "auxiliary_storage_labeling_positionx" ,
"auxiliary_storage_labeling_positiony" ))) 
 > x(make_point( 
"auxiliary_storage_labeling_positionx" , 
"auxiliary_storage_labeling_positiony"
)),'Right','Left')

and something similar for the vertical alignment:

if(y(closest_point($geometry,
make_point( 
"auxiliary_storage_labeling_positionx" , 
"auxiliary_storage_labeling_positiony" ))) < 
y(make_point( 
"auxiliary_storage_labeling_positionx" , 
"auxiliary_storage_labeling_positiony" 
)),'Bottom','Top')

the 'closest_point' statement you'll only need if the geometry is polygon or line.

for the Centered position you can change the expression and add a variable d for a treshold (e.g. in meters) in which the label will be centered:

with_variable ('d', 200,
CASE
WHEN 
(x(closest_point($geometry,
 make_point( "auxiliary_storage_labeling_positionx" ,
"auxiliary_storage_labeling_positiony" ))) 
< x(make_point( 
"auxiliary_storage_labeling_positionx" , 
"auxiliary_storage_labeling_positiony"
))-@d)
THEN 'Left' 
WHEN
(x(closest_point($geometry,
 make_point( "auxiliary_storage_labeling_positionx" ,
"auxiliary_storage_labeling_positiony" ))) 
> @d+x(make_point( 
"auxiliary_storage_labeling_positionx" , 
"auxiliary_storage_labeling_positiony"
))) THEN 'Right'
ELSE 'Center' END)

enter image description here

  • That works really good, with the exception of the situation where the label is directly above the geometry. in that case it moves the label off to one side or the other. I'd like to also be able to place a label like the first picture in my question.. – Troy Buerge Apr 14 at 20:43
  • I have added a expression for the horizontal with something like a treshold (variable d in meters) . between +d and -d around the label it will be centered. – eurojam Apr 15 at 5:00
  • That's getting better. The issue is that it fails quit badly when there are a large range in label lengths, or when changing zoom levels. Is there any way to get the length of the label in meters on the map? – Troy Buerge Apr 16 at 0:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.