Poster Design: Styles draws the Bless wall panels from the shared panel geometry
wall.bless-panels drew nothing. It now draws the ladder's 5 x 8 ft size (60x96: three 60 x 36 in sheets, 6 in joins) through panelSheets' planPanels and screenLayout, the same plan the Bless print uses: the sheets pulled apart, each join a red glue band with a dashed edge, a banner on the first sheet, a footer on the last, and rows of portrait cards inside each sheet's content box, never crossing a join. The cards are a layout (src/panelsSvg.js): the Bless wall draws its real cards in its own plugin, which the gallery cannot import. The card is not offered for printing here.
This commit is contained in:
parent
02ba16a7de
commit
fd43836920
3 changed files with 86 additions and 6 deletions
|
|
@ -25,6 +25,8 @@ import countryData from '@map/data/country-posters.json'
|
|||
import { makeCountrySheet } from '@map/packet/countrySheet.js'
|
||||
import { loadPacketStrings } from '@map/packet/packetStrings.js'
|
||||
import { firstPageImage } from './src/pageThumb.js'
|
||||
import { panelsSvgUrl } from './src/panelsSvg.js'
|
||||
import { resolvePosterSize } from '@map/constants/posterSizes.js'
|
||||
import { listConfigurations, FAMILY_KEYS, SAMPLE_COUNTRY_ID } from './src/templates.js'
|
||||
import FullDetailsDialog from './src/FullDetailsDialog.vue'
|
||||
|
||||
|
|
@ -96,7 +98,12 @@ async function packetDocument(variant) {
|
|||
const doc = R.buildPacket(sample, rows, new Map(), mapSvg, null, null, variant, null)
|
||||
return { html: doc, page: '.sheet', width: R.W, height: R.H, firstPageOnly: true }
|
||||
}
|
||||
const ctx = { countrySheet, cardDeck, packetDocument }
|
||||
// A multi-sheet poster as its panels, from the shared ladder's sheets for that size.
|
||||
function panels(sizeKey) {
|
||||
const size = resolvePosterSize(sizeKey)
|
||||
return size ? { image: panelsSvgUrl(size.sheets) } : null
|
||||
}
|
||||
const ctx = { countrySheet, cardDeck, packetDocument, panels }
|
||||
|
||||
// The printed document's size, measured when it is drawn: what "file size" means in the details.
|
||||
// render() answers a poster's HTML (a map sheet) or a document { html, page, width, height } (a deck, a packet).
|
||||
|
|
@ -105,6 +112,7 @@ async function renderDocument(name) {
|
|||
const c = byName.get(name)
|
||||
if (!c || !c.render) return null
|
||||
const out = await c.render(ctx)
|
||||
if (out && out.image) return out
|
||||
const html = typeof out === 'string' ? out : out && out.html
|
||||
if (!html) return null
|
||||
if (!(out && out.firstPageOnly)) fileBytes.value = { ...fileBytes.value, [name]: new Blob([html]).size }
|
||||
|
|
@ -117,6 +125,7 @@ async function renderDocument(name) {
|
|||
async function previewSrc(item) {
|
||||
const out = await renderDocument(item.id)
|
||||
if (!out) return null
|
||||
if (out.image) return out.image
|
||||
if (typeof out === 'object') return firstPageImage(out.html, out)
|
||||
const { rasterPoster, looksRendered } = await import('@map/packet/poster-raster.js')
|
||||
const blob = await rasterPoster(out, { scale: 0.25 })
|
||||
|
|
@ -130,7 +139,7 @@ async function previewSrc(item) {
|
|||
// packet missing its later pages would misrepresent the template.
|
||||
async function sheet(item) {
|
||||
const out = await renderDocument(item.id)
|
||||
if (!out || (typeof out === 'object' && out.firstPageOnly)) return ''
|
||||
if (!out || out.image || (typeof out === 'object' && out.firstPageOnly)) return ''
|
||||
return typeof out === 'string' ? out : out.html
|
||||
}
|
||||
|
||||
|
|
|
|||
69
plugin-designs/poster-design/src/panelsSvg.js
Normal file
69
plugin-designs/poster-design/src/panelsSvg.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* panelsSvg.js: a poster printed on several sheets, drawn as the sheets pulled apart, each join a red glue
|
||||
* band, as one SVG image for a poster card's thumbnail.
|
||||
*
|
||||
* The geometry is the shared panel plan (library/components/poster/panelSheets.js planPanels + screenLayout):
|
||||
* the same sheets, joins and content boxes the print uses. Inside each sheet's content box sit rows of cards,
|
||||
* the way the Bless wall fills its 5 × 8 ft panels: a banner on the first sheet, a footer on the last, and
|
||||
* card rows that never cross a join. The cards are a LAYOUT (blocks, no words): the Bless wall draws its real
|
||||
* cards in its own plugin, which a library-only gallery cannot import.
|
||||
*/
|
||||
import { planPanels, screenLayout } from '@map/components/poster/panelSheets.js'
|
||||
|
||||
const PAPER = '#f7f4ec'
|
||||
const INK = '#3b463d'
|
||||
const ACCENT = '#6B4A78' // the Bless wall's purple
|
||||
const PHOTO = '#e9e3d4'
|
||||
const LINE = '#c9c3b3'
|
||||
|
||||
/**
|
||||
* @param {{ sheetW, sheetH, count, direction, joinIn }} sheets a size's `sheets` from the shared ladder
|
||||
* @param {{ borderIn?: number, gapIn?: number, cols?: number }} o
|
||||
* @returns {string} an image URL (a data: URL of an SVG), drawn in inches
|
||||
*/
|
||||
export function panelsSvgUrl(sheets, { borderIn = sheets.joinIn || 2, gapIn = 0.75, cols = 14 } = {}) {
|
||||
const plan = planPanels({ ...sheets, borderIn, joinFill: 'glue' })
|
||||
const L = screenLayout(plan, { gapIn, pxPerIn: 1 })
|
||||
const W = L.worldW, H = L.worldH
|
||||
const s1 = Math.min(plan.sheetW, plan.sheetH)
|
||||
const stroke = s1 / 200
|
||||
let out = ''
|
||||
for (const sh of plan.sheets) {
|
||||
const at = L.sheets[sh.s]
|
||||
const ox = at.x, oy = at.y
|
||||
out += `<rect x="${ox}" y="${oy}" width="${plan.sheetW}" height="${plan.sheetH}" fill="${PAPER}" stroke="${LINE}" stroke-width="${stroke}"/>`
|
||||
const c = sh.content
|
||||
let top = oy + c.y0, bottom = oy + c.y1
|
||||
const cw0 = c.x1 - c.x0
|
||||
if (sh.first) { // the banner: a title band and the prayer-themes table
|
||||
const bh = cw0 * 0.075, th = cw0 * 0.17
|
||||
out += `<rect x="${ox + c.x0}" y="${top}" width="${cw0}" height="${bh}" fill="${INK}"/>`
|
||||
out += `<rect x="${ox + c.x0}" y="${top + bh + cw0 * 0.01}" width="${cw0}" height="${th}" fill="none" stroke="${ACCENT}" stroke-width="${stroke * 2}"/>`
|
||||
top += bh + th + cw0 * 0.025
|
||||
}
|
||||
if (sh.last) { // the footer: the blessing and the closing line
|
||||
const fh = cw0 * 0.09
|
||||
out += `<rect x="${ox + c.x0}" y="${bottom - fh}" width="${cw0}" height="${fh}" fill="${ACCENT}" opacity=".85"/>`
|
||||
bottom -= fh + cw0 * 0.015
|
||||
}
|
||||
// rows of portrait cards (0.8 aspect), centred in the band, never crossing a join
|
||||
const cw = cw0 / cols, ch = cw / 0.8
|
||||
const rows = Math.max(0, Math.floor((bottom - top) / ch))
|
||||
const y0 = top + Math.max(0, (bottom - top) - rows * ch) / 2
|
||||
for (let r = 0; r < rows; r++) {
|
||||
for (let k = 0; k < cols; k++) {
|
||||
const x = ox + c.x0 + k * cw, y = y0 + r * ch
|
||||
out += `<rect x="${x + cw * 0.08}" y="${y + ch * 0.06}" width="${cw * 0.84}" height="${cw * 0.84}" fill="${PHOTO}"/>`
|
||||
out += `<rect x="${x + cw * 0.15}" y="${y + ch * 0.06 + cw * 0.9}" width="${cw * 0.7}" height="${ch * 0.06}" fill="${INK}" opacity=".7"/>`
|
||||
}
|
||||
}
|
||||
if (sh.band) { // the glue band: red, dashed at its edge, as PanelSheets draws it
|
||||
const b = sh.band
|
||||
const ex = plan.direction === 'vertical' ? `x1="${ox}" y1="${oy + b.h}" x2="${ox + b.w}" y2="${oy + b.h}"` : `x1="${ox + b.w}" y1="${oy}" x2="${ox + b.w}" y2="${oy + b.h}"`
|
||||
out += `<rect x="${ox + b.x}" y="${oy + b.y}" width="${b.w}" height="${b.h}" fill="rgba(176,0,0,.14)"/>`
|
||||
out += `<line ${ex} stroke="#b00" stroke-width="${stroke * 1.5}" stroke-dasharray="${stroke * 6} ${stroke * 4}"/>`
|
||||
}
|
||||
}
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${(W * 4).toFixed(0)}" height="${(H * 4).toFixed(0)}">${out}</svg>`
|
||||
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
|
||||
}
|
||||
|
|
@ -10,7 +10,8 @@
|
|||
* render(ctx) draws the template from the LIBRARY with the sample data, so a library change shows up in
|
||||
* the gallery the next time it opens. It returns either a poster's HTML (a map sheet: an <svg> the poster
|
||||
* rasteriser lifts) or a printable DOCUMENT as { html, page, width, height } (a deck, a packet: HTML pages,
|
||||
* whose first page becomes the thumbnail, src/pageThumb.js). Entries the gallery cannot draw yet
|
||||
* whose first page becomes the thumbnail, src/pageThumb.js) or a ready image as { image } (panels drawn from
|
||||
* the shared panel geometry, src/panelsSvg.js). Entries the gallery cannot draw yet
|
||||
* say so (render: null) and the card shows the wall's "preview unavailable" placeholder; the details
|
||||
* dialog states which part is missing, rather than a picture of something else.
|
||||
*
|
||||
|
|
@ -96,10 +97,11 @@ export function listConfigurations() {
|
|||
family: 'wall',
|
||||
labelKey: 'posterDesign.tpl.blessPanels',
|
||||
size: '5 × 8 ft, 3 panels',
|
||||
renderer: 'plugin-designs/wall-of-people-groups/src/blessPoster.js (not in library/ yet)',
|
||||
settings: {},
|
||||
renderer: 'library/components/poster/panelSheets.js planPanels (the sheets, joins and content boxes); the cards are drawn by plugin-designs/wall-of-people-groups/src/blessPoster.js',
|
||||
settings: { size: '60x96', joinFill: 'glue' },
|
||||
sample: null,
|
||||
render: null,
|
||||
// The panel geometry of the ladder's 5 × 8 ft size, with the card rows as a layout (src/panelsSvg.js).
|
||||
render: (ctx) => ctx.panels('60x96'),
|
||||
missing: 'posterDesign.missing.bless',
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue