Exemple #1
0
def output_to_html_element(mro: gws.MapRenderOutput,
                           wrap='relative') -> gws.XmlElement:
    w, h = mro.view.size_mm

    css_size = f'left:0;top:0;width:{int(w)}mm;height:{int(h)}mm'
    css_abs = f'position:absolute;{css_size}'

    tags: t.List[gws.XmlElement] = []

    for plane in mro.planes:
        if plane.type == 'image':
            img_path = gws.tempname('mro.png')
            plane.image.to_path(img_path)
            tags.append(xml2.tag('img', {'style': css_abs, 'src': img_path}))
        if plane.type == 'path':
            tags.append(xml2.tag('img', {'style': css_abs, 'src': plane.path}))
        if plane.type == 'svg':
            tags.append(
                gws.lib.svg.fragment_to_element(plane.elements,
                                                {'style': css_abs}))

    css_div = None
    if wrap and wrap in {'relative', 'absolute', 'fixed'}:
        css_div = f'position:{wrap};overflow:hidden;{css_size}'
    return xml2.tag('div', {'style': css_div}, *tags)
Exemple #2
0
def _marker(uid, sv: gws.StyleValues) -> gws.XmlElement:
    size = sv.marker_size or DEFAULT_MARKER_SIZE
    size2 = size // 2

    content = None
    atts: dict = {}

    _add_paint_atts(atts, sv, 'marker_')

    if sv.marker == 'circle':
        atts.update({
            'cx': size2,
            'cy': size2,
            'r': size2,
        })
        content = 'circle', atts

    if content:
        return xml2.tag(
            'marker', {
                'id': uid,
                'viewBox': f'0 0 {size} {size}',
                'refX': size2,
                'refY': size2,
                'markerUnits': 'userSpaceOnUse',
                'markerWidth': size,
                'markerHeight': size,
            }, content)
Exemple #3
0
def soup_to_fragment(view: gws.MapView, points: t.List[gws.Point],
                     tags: t.List[t.Any]) -> t.List[gws.XmlElement]:
    """Convert an svg "soup" to a list of XmlElements.

    A soup has two components:

    - a list of points, in the map coordinate system
    - a list of tuples suitable for `xml2.tag` input (tag-name, {atts}, child1, child2....)

    The idea is to represent client-side svg drawings (e.g. dimensions) in a resolution-independent way

    First, points are converted to pixels using the view's transform. Then, each tag's attributes are iterated.
    If any attribute value is an array, it's assumed to be a 'function'.
    The first element is a function name, the rest are arguments.
    Attribute 'functions' are

    - ['x', n] - returns points[n][0]
    - ['y', n] - returns points[n][1]
    - ['r', p1, p2, r] - computes a slope between points[p1] points[p2] and returns a string
        `rotate(slope, points[r].x, points[r].y)`

    """

    trans = gws.gis.render.map_view_transformer(view)
    px = [trans(*p) for p in points]

    def eval_func(v):
        if v[0] == 'x':
            return round(px[v[1]][0])
        if v[0] == 'y':
            return round(px[v[1]][1])
        if v[0] == 'r':
            a = _slope(px[v[1]], px[v[2]])
            adeg = math.degrees(a)
            x, y = px[v[3]]
            return f'rotate({adeg:.0f}, {x:.0f}, {y:.0f})'

    def convert(tag):
        for arg in tag:
            if isinstance(arg, (list, tuple)):
                convert(arg)
            elif isinstance(arg, dict):
                for k, v in arg.items():
                    if isinstance(v, (list, tuple)):
                        arg[k] = eval_func(v)

    els = []

    for tag in tags:
        convert(tag)
        els.append(xml2.tag(*tag))

    return els
Exemple #4
0
def shape_to_element(shape: gws.IShape,
                     precision=0,
                     axis: gws.Axis = gws.AXIS_XY,
                     crs_format: gws.CrsFormat = gws.CrsFormat.URN,
                     with_ns='gml') -> gws.XmlElement:
    """Convert a Shape to a GML3 geometry element."""

    geom: shapely.geometry.base.BaseGeometry = getattr(shape, 'geom')
    srs = shape.crs.to_string(crs_format)
    ns = (with_ns + ':') if with_ns else ''

    opts = gws.Data(precision=precision, axis=axis, ns=ns)

    return xml2.tag(*_tag(geom, opts), srsName=srs)
Exemple #5
0
def _geometry(geom: shapely.geometry.base.BaseGeometry,
              atts: dict = None) -> gws.XmlElement:
    def _xy(xy):
        x, y = xy
        return f'{x} {y}'

    def _lpath(coords):
        ps = []
        cs = iter(coords)
        for c in cs:
            ps.append(f'M {_xy(c)}')
            break
        for c in cs:
            ps.append(f'L {_xy(c)}')
        return ' '.join(ps)

    gt = _geom_type(geom)

    if gt == _TYPE_POINT:
        g = t.cast(shapely.geometry.Point, geom)
        return xml2.tag('circle', {'cx': int(g.x), 'cy': int(g.y)}, atts)

    if gt == _TYPE_LINESTRING:
        g = t.cast(shapely.geometry.LineString, geom)
        d = _lpath(g.coords)
        return xml2.tag('path', {'d': d}, atts)

    if gt == _TYPE_POLYGON:
        g = t.cast(shapely.geometry.Polygon, geom)
        d = ' '.join(
            _lpath(interior.coords) + ' z' for interior in g.interiors)
        d = _lpath(g.exterior.coords) + ' z ' + d
        return xml2.tag('path', {'fill-rule': 'evenodd', 'd': d.strip()}, atts)

    if gt > _TYPE_MULTI:
        g = t.cast(shapely.geometry.base.BaseMultipartGeometry, geom)
        return xml2.tag('g', *[_geometry(p, atts) for p in g.geoms])
Exemple #6
0
def _label_text(cx, cy, label, sv: gws.StyleValues) -> gws.XmlElement:
    font_name = _font_name(sv)
    font_size = sv.label_font_size or DEFAULT_FONT_SIZE
    font = gws.lib.font.from_name(font_name, font_size)

    anchor = 'start'

    if sv.label_align == 'right':
        anchor = 'end'
    elif sv.label_align == 'center':
        anchor = 'middle'

    atts = {'text-anchor': anchor}

    _add_font_atts(atts, sv, 'label_')
    _add_paint_atts(atts, sv, 'label_')

    lines = label.split('\n')
    _, em_height = font.getsize('MMM')
    metrics = [font.getsize(s) for s in lines]

    line_height = sv.label_line_height or 1
    padding = sv.label_padding or [0, 0, 0, 0]

    ly = cy - padding[2]
    lx = cx

    if anchor == 'start':
        lx += padding[3]
    elif anchor == 'end':
        lx -= padding[1]
    else:
        lx += padding[3] // 2

    height = em_height * len(lines) + line_height * (
        len(lines) - 1) + padding[0] + padding[2]

    pad_bottom = metrics[-1][1] - em_height
    if pad_bottom > 0:
        height += pad_bottom
    ly -= pad_bottom

    spans = []
    for s in reversed(lines):
        spans.append(['tspan', {'x': lx, 'y': ly}, s])
        ly -= (em_height + line_height)

    tags = []

    tags.append(('text', atts, *reversed(spans)))

    # @TODO a hack to emulate 'paint-order' which wkhtmltopdf doesn't seem to support
    # place a copy without the stroke above the text
    if atts.get('stroke'):
        no_stroke_atts = {
            k: v
            for k, v in atts.items() if not k.startswith('stroke')
        }
        tags.append(('text', no_stroke_atts, *reversed(spans)))

    # @TODO label backgrounds don't really work
    if sv.label_background:
        width = max(xy[0] for xy in metrics) + padding[1] + padding[3]

        if anchor == 'start':
            bx = cx
        elif anchor == 'end':
            bx = cx - width
        else:
            bx = cx - width // 2

        ratts = {
            'x': bx,
            'y': cy - height,
            'width': width,
            'height': height,
            'fill': sv.label_background,
        }

        tags.insert(0, ('rect', ratts))

    # a hack to move labels forward: emit a (non-supported) z-index attribute
    # and sort elements by it later on (see `fragment_to_element`)

    return xml2.tag('g', {'z-index': 100}, *tags)
def to_xml(ARGS, tag):
    if ARGS.with_soap:
        tag = 'soap:Envelope', ('soap:Header', ''), ('soap:Body', tag)
    el = xml2.tag(*tag)
    xml = xml2.to_string(el, with_xml=True, with_xmlns=True, with_schemas=True)
    return gws.ContentResponse(content=xml, mime=gws.lib.mime.XML)
Exemple #8
0
def sanitize_element(el: gws.XmlElement) -> t.Optional[gws.XmlElement]:
    children = gws.compact(_sanitize(c) for c in el.children)
    if children:
        return xml2.tag('svg', _sanitize_atts(el.attributes), *children)
Exemple #9
0
def fragment_to_element(fragment: t.List[gws.XmlElement],
                        atts: dict = None) -> gws.XmlElement:
    fr = sorted(fragment, key=lambda el: el.attributes.get('z-index', 0))
    return xml2.tag('svg', _SVG_TAG_ATTS, atts, *fr)