Added previews to image autocomplete imputs.

This commit is contained in:
orangemug
2020-09-16 14:29:36 +01:00
parent 63b14933ba
commit 20ac0511e6
6 changed files with 134 additions and 13 deletions

View File

@@ -293,8 +293,20 @@ export default class App extends React.Component {
}
updateIcons(baseUrl) {
downloadSpriteMetadata(baseUrl, icons => {
this.setState({ spec: updateRootSpec(this.state.spec, 'sprite', icons)})
downloadSpriteMetadata(baseUrl, metadata => {
const {spec} = this.state;
this.setState({
spec: {
...spec,
$root: {
...spec.$root,
sprite: {
...spec.$root["sprite"],
metadata: metadata
}
}
}
})
})
}

View File

@@ -12,6 +12,7 @@ import InputDynamicArray from './InputDynamicArray'
import InputFont from './InputFont'
import InputAutocomplete from './InputAutocomplete'
import InputEnum from './InputEnum'
import SpriteIcon from './SpriteIcon'
import capitalize from 'lodash.capitalize'
const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image']
@@ -85,10 +86,21 @@ export default class SpecField extends React.Component {
case 'formatted':
case 'string':
if (iconProperties.indexOf(this.props.fieldName) >= 0) {
const options = this.props.fieldSpec.values || [];
const {metadata} = this.props.fieldSpec;
const options = Object.entries(metadata && metadata.data ? metadata.data : {});
return <InputAutocomplete
{...commonProps}
options={options.map(f => [f, f])}
options={options.map(([k,v]) => {
return [
k,
<SpriteIcon
metadata={metadata}
maxWidth={120}
id={k}
data={v}
/>
];
})}
/>
} else {
return <InputString

View File

@@ -13,7 +13,7 @@ function getFieldSpec(spec, layerType, fieldName) {
if(iconProperties.indexOf(fieldName) >= 0) {
return {
...fieldSpec,
values: spec.$root.sprite.values
metadata: spec.$root.sprite.metadata
}
}
if(fieldName === 'text-font') {

View File

@@ -0,0 +1,57 @@
import React from 'react'
export default function SpriteIcon (props) {
const {metadata, id, data, maxWidth} = props;
const {image} = metadata;
const pixelRatio = Math.max(window.devicePixelRatio, 2);
function getUrls (pixelRatio, url) {
const out = [];
for (var i=pixelRatio; i>=1; i--) {
if (i > 1) {
out.push(
url.replace(/.png/, `@${i}x.png`)
);
}
else {
out.push(url);
}
}
return out.map(url => {
return `url(${url})`;
}).join(", ");
}
let scale = 1;
if (data.width > maxWidth) {
scale = maxWidth/data.width;
}
const spriteWidth = image.width * scale;
const spriteHeight = image.height * scale;
const width = data.width * scale;
const height = data.height * scale;
const x = data.x * scale;
const y = data.y * scale;
return <div className="maputnik-sprite-icon">
<div className="maputnik-sprite-icon__text">
{id}
</div>
{image &&
<div className="maputnik-sprite-icon__icon">
<div
style={{
width: width,
height: height,
backgroundImage: getUrls(pixelRatio, metadata.imageUrl),
backgroundSize: `${spriteWidth}px ${spriteHeight}px`,
backgroundPosition: `${-x}px ${-y}px`
}}
/>
</div>
}
</div>
}

View File

@@ -1,22 +1,28 @@
import npmurl from 'url'
function loadJSON(url, defaultValue, cb) {
fetch(url, {
return fetch(url, {
mode: 'cors',
credentials: "same-origin"
})
.then(function(response) {
return response.json();
})
.then(function(body) {
cb(body)
})
.catch(function() {
console.warn('Can not metadata for ' + url)
cb(defaultValue)
return defaultValue;
})
}
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = (err) => reject(err);
img.src = url;
});
}
export function downloadGlyphsMetadata(urlTemplate, cb) {
if(!urlTemplate) return cb([])
@@ -31,11 +37,30 @@ export function downloadGlyphsMetadata(urlTemplate, cb) {
}
let url = npmurl.format(urlObj);
loadJSON(url, [], cb)
loadJSON(url, []).then(cb);
}
export function downloadSpriteMetadata(baseUrl, cb) {
if(!baseUrl) return cb([])
const url = baseUrl + '.json'
loadJSON(url, {}, glyphs => cb(Object.keys(glyphs)))
const jsonUrl = baseUrl + '.json'
const imageUrl = baseUrl + '.png'
Promise.all([
loadImage(imageUrl).catch(() => undefined),
loadJSON(jsonUrl, {}),
])
.then(([image, data]) => {
const out = {
jsonUrl,
imageUrl,
data
};
if (image) {
out.image = {
width: image.naturalWidth,
height: image.naturalHeight,
}
}
cb(out);
});
}

View File

@@ -167,3 +167,18 @@
}
}
.maputnik-sprite-icon {
display: flex;
}
.maputnik-sprite-icon__text {
flex: 1;
}
.maputnik-sprite-icon__icon {
margin-left: 0.6em;
padding: 2px;
background-color: white;
background-size: 8px 8px;
background-position: 0 0, 4px 4px;
}