Skip to content

Commit

Permalink
refactored support for map marker customisation
Browse files Browse the repository at this point in the history
  • Loading branch information
xrotwang committed May 20, 2023
1 parent 8373513 commit d3cc63e
Show file tree
Hide file tree
Showing 17 changed files with 155 additions and 64 deletions.
6 changes: 6 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
Changes
-------

Unreleased
~~~~~~~~~~

- Refactored support for map marker customisation


10.0.0
~~~~~~

Expand Down
9 changes: 6 additions & 3 deletions src/clld/db/models/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

from zope.interface import implementer
from clldutils.misc import lazyproperty
from clldutils.color import qualitative_colors

from clld.db.meta import Base, PolymorphicBaseMixin, DBSession
from clld.web.icon import Icon
from clld import interfaces
from clld.web.icon import ORDERED_ICONS

from . import (
IdNameDescriptionMixin,
Expand Down Expand Up @@ -131,10 +132,12 @@ def domain(self):
"""
d = collections.OrderedDict()
for i, des in enumerate(itertools.product(*[p.domain for p in self.parameters])):
cde = CombinationDomainElement(
self, des, icon=ORDERED_ICONS[i % len(ORDERED_ICONS)])
cde = CombinationDomainElement(self, des)
d[cde.number] = cde

for cde, color in zip(d.values(), qualitative_colors(i + 1)):
cde.icon = Icon(color.replace('#', 'c'))

for language, values in itertools.groupby(
sorted(self.values, key=lambda v: v.valueset.language_pk),
lambda i: i.valueset.language,
Expand Down
4 changes: 3 additions & 1 deletion src/clld/web/adapters/geojson.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from clldutils.misc import nfilter

from clld.web.adapters.base import Renderable
from clld.web.icon import Icon
from clld import interfaces
from clld.db.meta import DBSession
from clld.db.models.common import ValueSet, Value, Language
Expand Down Expand Up @@ -215,8 +216,9 @@ class GeoJsonCombinationDomainElement(GeoJson):
"""GeoJSON adapter for a domain element of a combination of parameters."""

def feature_properties(self, ctx, req, language):
icon = Icon.from_req(ctx, req) or ctx.icon
return {
'icon': ctx.icon.url(req) if ctx.icon else '',
'icon': icon.url(req) if icon else '',
'zindex': 1000 - len(ctx.languages)}


Expand Down
66 changes: 63 additions & 3 deletions src/clld/web/icon.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import itertools

from clldutils import svg
from clldutils.color import rgb_as_hex
from zope.interface import implementer
from clld.interfaces import IIcon, IMapMarker

from clld.interfaces import IIcon, IMapMarker, IValue, IValueSet, IDomainElement

SHAPES = [
"c", # circle
Expand Down Expand Up @@ -71,11 +72,70 @@ class Icon(object):

"""Default implementation of IIcon: Icons are static image files."""

def __init__(self, name):
def __init__(self, name, opacity=None, select_id=None):
self.name = name
self.opacity = opacity
self.select_id = select_id

@classmethod
def from_req(cls,
ctx,
req,
icon_spec_factory=None,
icon_map=None):
from clld.db.models.common import CombinationDomainElement # Avoid circular imports.

de, icon, opacity, select_id = None, None, '1.0', None
icon_map = icon_map or {}

if IValue.providedBy(ctx):
de = ctx.domainelement
elif IValueSet.providedBy(ctx):
de = ctx.values[0].domainelement
elif IDomainElement.providedBy(ctx):
de = ctx
elif isinstance(ctx, CombinationDomainElement):
select_id = 'v' + ctx.id
icon = req.params.get(select_id, ctx.icon.name)

if de:
select_id = 'v{}'.format(de.number)
icon = req.params.get(select_id, de.jsondata['icon'])

if not icon and icon_spec_factory:
icon = icon_spec_factory(ctx, req)
if isinstance(icon, tuple):
icon, select_id = icon

if icon:
opacity = None
if "'" in icon:
icon = icon.split("'")[0]
if len(icon) > 4:
if len(icon) == 9:
opacity = int('0x' + icon[7:], base=16) / 255
icon = icon[:7]
elif len(icon) == 7:
pass
else:
icon = icon[:4]
if len(icon) == 4:
icon = icon[0] + 2 * icon[1] + 2 * icon[2] + 2 * icon[3]
return cls(icon_map.get(icon, icon), opacity=opacity, select_id=select_id)

@property
def shape(self):
return self.name[0]

@property
def color(self):
res = rgb_as_hex(self.name[1:7])
if self.opacity:
res += hex(round(float(self.opacity) * 255))[2:]
return res

def url(self, req):
return svg.data_url(svg.icon(self.name))
return svg.data_url(svg.icon(self.name, opacity=str(self.opacity)))


#: a list of all available icons:
Expand Down
7 changes: 6 additions & 1 deletion src/clld/web/maps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ def get_options_from_req(self):
res['center'] = list(map(float, [params['lat'], params['lng']]))
if 'z' in params:
res['zoom'] = int(params['z'])
if 'iconsize' in params:
res['icon_size'] = int(params['iconsize'])
if 'labels' in params:
res['show_labels'] = params['labels'] == '1'
except (ValueError, TypeError):
pass
return res
Expand Down Expand Up @@ -269,9 +273,10 @@ def get_legends(self):
stay_open=True,
item_attrs=dict(style='clear: right'))
items = []
iconsize = self.options.get('icon_size', 30)
for size in [15, 20, 30, 40]:
attrs = dict(name="iconsize", value=str(size), type="radio")
if size == self.options.get('icon_size', 30):
if size == iconsize:
attrs['checked'] = 'checked'
items.append(HTML.label(
HTML.input(onclick=helpers.JS_CLLD.mapResizeIcons(self.eid), **attrs),
Expand Down
1 change: 1 addition & 0 deletions src/clld/web/static/css/coloris.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added src/clld/web/static/fonts/CharisSIL-Bold.ttf
Binary file not shown.
Binary file not shown.
Binary file added src/clld/web/static/fonts/CharisSIL-Italic.ttf
Binary file not shown.
Binary file added src/clld/web/static/fonts/CharisSIL-Regular.ttf
Binary file not shown.
23 changes: 20 additions & 3 deletions src/clld/web/static/js/clld.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,28 @@ CLLD.url = function(path, query) {
/**
* Reload the current page with updated query parameters.
*/
CLLD.reload = function (query, url) {
CLLD.reload = function (query, url, fragment) {
var current = document.location;
url = url === undefined ? current.pathname : url;
if (current.search) {
query = $.extend({}, JSON.parse('{"' + decodeURI(current.search.replace('?', '').replace(/&/g, "\",\"").replace(/=/g,"\":\"")) + '"}'), query)
}
document.location.href = url + '?' + $.param(query);
if (fragment === undefined) {
document.location.href = url + '?' + $.param(query);
} else {
document.location.href = url + '?' + $.param(query) + '#' + fragment;
}
};

CLLD.reload_map = function (domain) {
var query = {
'iconsize': $('input[name=iconsize]:checked').val(),
'labels': $('input[id=map-label-visiblity]').is(':checked') ? '1' : '0'
};
for (const sid of domain) {
query[sid] = $("#" + sid + "-c").val().replace("#", $("#" + sid + "-s").val());
}
CLLD.reload(query, undefined, 'map-container');
};

/**
Expand Down Expand Up @@ -575,7 +590,9 @@ CLLD.Map = function(eid, layers, options) {
}

if (this.options.hash) {/* istanbul ignore next */
hash = new L.Hash(this.map);
if (!window.location.hash) {
hash = new L.Hash(this.map);
}
}

/* istanbul ignore if */
Expand Down

0 comments on commit d3cc63e

Please sign in to comment.