Here's a somewhat approximate (but hopefully effective) way to do it.
First some math. We need to figure out how many characters at a certain font-size a feature can contain. Here things / assumptions to know:
- assuming metric units, (added slight change below which may make this work for us foot crs.)
- font size is a measure of font height. Most font's are about half as wide as they are high.
- using pt for font height, 1pt is roughtly 0.035CM
- assuming your parcels are roughly rectangular / regular
To find how long an item is on screen / print we can use it's longest dimension (length or hight, or just length if your labels are horizontal only) / scale * 100 (to go from M to CM)
Then we can see if our label would fit.
You could do it all in the expression engine, but a custom python expression would be more efficient. Here is a tutorial on how to create one.
My custom expression:
from qgis.core import *
from qgis.gui import *
@qgsfunction(args='auto', group='Custom')
def labelFits(labelStr, fontPt, scaleM, feature, parent):
# returns true if a label will fit in the feature at a given
# font size and scale
bbox = feature.geometry().boundingBox()
# for CRS in us foot
# fontWidth = fontPt * 0.0875
# for CRS in metric
# 1pt = 0.035CM
fontWidth = fontPt * 0.035 * 0.5
# length of maximum dimension on-screen/print in CM
labelRoom = max(bbox.width(),bbox.height()) / scaleM * 100
# approx length of our label in CM based on font height * 0.5
labelLen = len(labelStr) * fontWidth
if labelRoom > labelLen:
return True
else:
return False
Then just use that expression in the label:
if(labelFits( "yourAttribute" , 8 , @map_scale ), "yourAttribute",$id)
You'll need to plug in whatever attribute you're actually using of course, and change the font size from 8 to whatever you're using. Also, since fonts vary quite a bit you may need to tweak it a little bit till it looks right.
You could also use that expression to do things like change the color based on if the label fits or not.