ui-mapbox icon indicating copy to clipboard operation
ui-mapbox copied to clipboard

Layer layout with "icon-text-fit-padding" not working in ios

Open MarkOdey opened this issue 3 years ago • 3 comments

Hello I am currently evaluating this library for a project and noticed some support differences between ios and android.

For this case, I am able to apply "icon-text-fit": "width" to resize icon to the text size for both environment but when I provide "icon-text-fit-padding" I get an error which breaks layer rendering in ios.

` this.mapbox .addLayer({ id: "store-locations", type: "symbol", source: "stores", filter: ["has", "label_en"], minzoom: 0, maxzoom: 20,

      layout: {
        "icon-opacity": ["case", ["has", "label_en"], 1, 0],
        "text-field": [
          "case",
          ["has", "label_en"],
          ["get", "label_en"],
          "",
        ],
        "icon-image": ["case", ["has", "label_en"], "box2", ""],
        "icon-text-fit": "width",
        "icon-text-fit-padding": [0, 0, 0, 0],

        "icon-size": 1,
        "text-font": ["Open Sans Regular", "Arial Unicode MS Regular"],
        "text-size": 12,
      },
    })
    .catch((e) => {
      console.log(e);
    });`

This is the error in IOS

Error: -[__NSCFNumber isEqualToString:]: unrecognized selector sent to instance 0xac6605cc1e5c96e6

I suspect that should be a supported attribute in ios as if I provide a wrong format I get an error that the format needs to be an array with 4 items.

MarkOdey avatar Nov 25 '22 17:11 MarkOdey

@MarkOdey i dont really use mapbox anymore though i might have a fix. Could you try to replace the content of node_modules/@nativescript-community/ui-mapbox/layers/parser/property-parser.ios.js with this?

import { Color } from '@nativescript/core';
function toCamelCase(s) {
    return s.replace(/([-_][a-z])/gi, ($1) => $1.toUpperCase().replace('-', '').replace('_', ''));
}
const styleExtras = {
    iconTextFitPadding: {
        iosType: 'edgeinsets',
    },
    iconOffset: {
        iosType: 'vector',
    },
    textOffset: {
        iosType: 'vector',
    },
    lineOffset: {
        iosType: 'vector',
    },
    fillTranslate: {
        iosType: 'vector',
    },
    lineTranslate: {
        iosType: 'vector',
    },
    iconTranslate: {
        iosType: 'vector',
    },
    textTranslate: {
        iosType: 'vector',
    },
    circleTranslate: {
        iosType: 'vector',
    },
    fillExtrusionTranslate: {
        iosType: 'vector',
    },
};
const keysMap = {
    'circle-pitch-scale': 'circleScaleAlignment',
    'circle-translate': 'circleTranslation',
    'circle-translate-anchor': 'circleTranslationAnchor',
    'fill-antialias': 'fillAntialiased',
    'fill-translate': 'fillTranslation',
    'fill-translate-anchor': 'fillTranslationAnchor',
    'icon-allow-overlap': 'iconAllowsOverlap',
    'icon-keep-upright': 'keepsIconUpright',
    'icon-ignore-placement': 'iconIgnoresPlacement',
    'icon-image': 'iconImageName',
    'icon-rotate': 'iconRotation',
    'icon-rotate-alignment': 'iconRotationAlignment',
    'icon-translate': 'iconTranslation',
    'icon-translate-anchor': 'iconTranslationAnchor',
    'icon-size': 'iconScale',
    'line-translate': 'lineTranslation',
    'line-translate-anchor': 'lineTranslationAnchor',
    'line-dasharray': 'lineDashPattern',
    'text-allow-overlap': 'textAllowsOverlap',
    'text-field': 'text',
    'text-font': 'textFontNames',
    'text-justify': 'textJustification',
    'text-ignore-placement': 'textIgnoresPlacement',
    'text-keep-upright': 'keepsTextUpright',
    'text-max-angle': 'maximumTextAngle',
    'text-max-width': 'maximumTextWidth',
    'text-rotate': 'textRotation',
    'text-rotate-alignment': 'textRotationAlignment',
    'text-size': 'textFontSize',
    'text-translate': 'textTranslation',
    'text-translate-anchor': 'textTranslationAnchor',
    'raster-hue-rotate': 'rasterHueRotation',
    'raster-resampling': 'rasterResamplingMode',
    'raster-brightness-min': 'maximumRasterBrightness',
    'raster-brightness-max': 'minimumRasterBrightness'
};
function transformValue(key, value, _styleType) {
    if (_styleType === 'color') {
        const color = value instanceof Color ? value : new Color(value);
        return color.ios;
    }
    else if (_styleType === 'vector') {
        const vector = CGVectorMake(value[0], value[1]);
        return NSExpression.expressionWithMGLJSONObject(NSValue.valueWithCGVector(vector));
    }
    else if (_styleType === "edgeinsets") {
        const edgeInsets = new UIEdgeInsets({
            top: value[0],
            left: value[1],
            bottom: value[2],
            right: value[3],
        });
        return NSExpression.expressionWithMGLJSONObject(NSValue.valueWithUIEdgeInsets(edgeInsets));
    }
    else {
        switch (key) {
            case 'raster-resampling':
                if (value === 'linear') {
                    return 0;
                }
                else if (value === 'nearest') {
                    return 1;
                }
                else {
                    return value;
                }
            default:
                return value;
        }
    }
}
export class PropertyParser {
    static parsePropertiesForLayer(propertiesObject) {
        const nProperties = {};
        if (propertiesObject) {
            Object.keys(propertiesObject).forEach((k) => {
                var _a;
                const actualKey = keysMap[k] || toCamelCase(k);
                const value = propertiesObject[k];
                const rValue = transformValue(k, value, (_a = styleExtras[k]) === null || _a === void 0 ? void 0 : _a.iosType);
                if (Array.isArray(value)) {
                    nProperties[actualKey] = NSExpression.expressionWithMGLJSONObject(rValue);
                }
                else {
                    nProperties[actualKey] = NSExpression.expressionForConstantValue(rValue);
                }
            });
        }
        return nProperties;
    }
    static propertyValueFromLayer(layer, key) {
        const actualKey = keysMap[key] || toCamelCase(key);
        const nValue = layer[actualKey];
        if (!nValue) {
            return null;
        }
        if (nValue.expressionType === 0) {
            if (nValue.constantValue instanceof UIColor) {
                return Color.fromIosColor(nValue.constantValue);
            }
            else {
                return nValue.constantValue;
            }
        }
        else {
            const expressionObj = nValue.mgl_jsonExpressionObject;
            const data = NSJSONSerialization.dataWithJSONObjectOptionsError(expressionObj, 0);
            const expression = NSString.alloc().initWithDataEncoding(data, NSUTF8StringEncoding);
            return JSON.parse(expression);
        }
    }
}
//# sourceMappingURL=property-parser.ios.js.map

If it works i ll make a new release

farfromrefug avatar Nov 29 '22 08:11 farfromrefug

Hello Thank you very much for your help.

I tried to put padding with your changes and still no luck.

the layer doesn't render and outputs this error :

Error: -[__NSCFNumber isEqualToString:]: unrecognized selector sent to instance 0xcce836faf54293da

Maybe I am misusing the edgeinsets data type.

Maybe I am unaware of a procedure for the changes to take effect.

Again thanks for your support.

MarkOdey avatar Nov 29 '22 19:11 MarkOdey

@MarkOdey ok can you create a repro example repo so that I can test and fix?

farfromrefug avatar Nov 29 '22 21:11 farfromrefug