aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/dumbymap.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'src/dumbymap.mjs')
-rw-r--r--src/dumbymap.mjs128
1 files changed, 78 insertions, 50 deletions
diff --git a/src/dumbymap.mjs b/src/dumbymap.mjs
index 8e26ee6..ee61838 100644
--- a/src/dumbymap.mjs
+++ b/src/dumbymap.mjs
@@ -3,7 +3,7 @@ import MarkdownItAnchor from 'markdown-it-anchor'
3import MarkdownItFootnote from 'markdown-it-footnote' 3import MarkdownItFootnote from 'markdown-it-footnote'
4import MarkdownItFrontMatter from 'markdown-it-front-matter' 4import MarkdownItFrontMatter from 'markdown-it-front-matter'
5import MarkdownItInjectLinenumbers from 'markdown-it-inject-linenumbers' 5import MarkdownItInjectLinenumbers from 'markdown-it-inject-linenumbers'
6import { renderWith, defaultAliases, parseConfigsFromYaml } from 'mapclay' 6import * as mapclay from 'mapclay'
7import { replaceTextNodes, onRemove, animateRectTransition, throttle, shiftByWindow } from './utils' 7import { replaceTextNodes, onRemove, animateRectTransition, throttle, shiftByWindow } from './utils'
8import { Layout, SideBySide, Overlay } from './Layout' 8import { Layout, SideBySide, Overlay } from './Layout'
9import * as utils from './dumbyUtils' 9import * as utils from './dumbyUtils'
@@ -86,6 +86,68 @@ export const markdown2HTML = (container, mdContent) => {
86} 86}
87 87
88/** 88/**
89 * defaultBlocks.
90 * @description Default way to get blocks from Semantic HTML
91 * @param {HTMLElement} root
92 */
93const defaultBlocks = root => {
94 const articles = root.querySelectorAll('article')
95 if (articles.length > 2) return articles
96
97 const others = Array.from(
98 root.querySelectorAll(':has(>p, >blockquote, >pre, >ul, >ol, >table, >details)'),
99 )
100 .map(e => {
101 e.classList.add('dumby-block')
102 return e
103 })
104 .filter(e => {
105 const isContained = e.parentElement.closest('.dumby-block')
106 if (isContained) e.classList.remove('dumby-block')
107 return !isContained
108 })
109
110 return others
111}
112
113/**
114 * updateAttributeByStep.
115 * @description Update data attribute by steps of map render
116 * @param {Object} - renderer which is running steps
117 */
118const updateAttributeByStep = ({ results, target, steps }) => {
119 let passNum = results.filter(
120 r => r.type === 'render' && r.state.match(/success|skip/),
121 ).length
122 const total = steps.length
123 passNum += `/${total}`
124
125 const final = results.filter(r => r.type === 'render').length === total
126
127 // FIXME HACK use MutationObserver for animation
128 if (!target.animations) target.animations = Promise.resolve()
129 target.animations = target.animations.then(async () => {
130 await new Promise(resolve => setTimeout(resolve, 100))
131 if (final) passNum += '\x20'
132 target.dataset.report = passNum
133
134 if (final) setTimeout(() => delete target.dataset.report, 100)
135 })
136}
137
138/** Get default render method by converter */
139const defaultRender = mapclay.renderWith(config => ({
140 use: config.use ?? 'Leaflet',
141 width: '100%',
142 ...config,
143 aliases: {
144 ...mapclay.defaultAliases,
145 ...(config.aliases ?? {}),
146 },
147 stepCallback: updateAttributeByStep,
148}))
149
150/**
89 * Generates maps based on the provided configuration 151 * Generates maps based on the provided configuration
90 * 152 *
91 * @param {HTMLElement} container - The container element for the maps 153 * @param {HTMLElement} container - The container element for the maps
@@ -96,16 +158,19 @@ export const markdown2HTML = (container, mdContent) => {
96 */ 158 */
97export const generateMaps = (container, { 159export const generateMaps = (container, {
98 crs = 'EPSG:4326', 160 crs = 'EPSG:4326',
161 initialLayout,
99 layouts = [], 162 layouts = [],
100 delay, 163 delay,
101 renderCallback, 164 renderCallback,
102 addBlocks = htmlHolder => Array.from(htmlHolder.querySelectorAll('article')), 165 addBlocks = defaultBlocks,
166 render = defaultRender,
103} = {}) => { 167} = {}) => {
104 /** Prepare Contaner/HTML-Holder/Showcase */ 168 /** Prepare Contaner */
105 container.classList.add('Dumby') 169 container.classList.add('Dumby')
106 delete container.dataset.layout 170 delete container.dataset.layout
107 container.dataset.layout = defaultLayouts[0].name 171 container.dataset.layout = initialLayout ?? defaultLayouts[0].name
108 172
173 /** Prepare Semantic HTML part and blocks of contents inside */
109 const htmlHolder = container.querySelector('.SemanticHtml, :has(article, section)') ?? container.firstElementChild 174 const htmlHolder = container.querySelector('.SemanticHtml, :has(article, section)') ?? container.firstElementChild
110 htmlHolder.classList.add('.SemanticHtml') 175 htmlHolder.classList.add('.SemanticHtml')
111 const blocks = addBlocks(htmlHolder) 176 const blocks = addBlocks(htmlHolder)
@@ -114,12 +179,13 @@ export const generateMaps = (container, {
114 b.dataset.total = blocks.length 179 b.dataset.total = blocks.length
115 }) 180 })
116 181
182 /** Prepare Showcase */
117 const showcase = document.createElement('div') 183 const showcase = document.createElement('div')
118 container.appendChild(showcase) 184 container.appendChild(showcase)
119 showcase.classList.add('Showcase') 185 showcase.classList.add('Showcase')
120 const renderPromises = []
121 186
122 /** Prepare Modal */ 187 /** Prepare Other Variables */
188 const renderPromises = []
123 const modalContent = document.createElement('div') 189 const modalContent = document.createElement('div')
124 container.appendChild(modalContent) 190 container.appendChild(modalContent)
125 const modal = new PlainModal(modalContent) 191 const modal = new PlainModal(modalContent)
@@ -392,63 +458,25 @@ export const generateMaps = (container, {
392 const elementsWithMapConfig = Array.from( 458 const elementsWithMapConfig = Array.from(
393 container.querySelectorAll(mapBlockSelector) ?? [], 459 container.querySelectorAll(mapBlockSelector) ?? [],
394 ) 460 )
395 /** 461 if (elementsWithMapConfig.length === 0) {
396 * updateAttributeByStep. 462 const map = document.createElement('pre')
397 * 463 map.textContent = '#Created by DumbyMap'
398 * @param {Object} - renderer which is running steps 464 htmlHolder.insertBefore(map, htmlHolder.firstElementChild)
399 */ 465 elementsWithMapConfig.push(map)
400 const updateAttributeByStep = ({ results, target, steps }) => {
401 let passNum = results.filter(
402 r => r.type === 'render' && r.state.match(/success|skip/),
403 ).length
404 const total = steps.length
405 passNum += `/${total}`
406
407 const final = results.filter(r => r.type === 'render').length === total
408
409 // FIXME HACK use MutationObserver for animation
410 if (!target.animations) target.animations = Promise.resolve()
411 target.animations = target.animations.then(async () => {
412 await new Promise(resolve => setTimeout(resolve, 100))
413 if (final) passNum += '\x20'
414 target.dataset.report = passNum
415
416 if (final) setTimeout(() => delete target.dataset.report, 100)
417 })
418 } 466 }
419 /**
420 * config converter for mapclay.renderWith()
421 *
422 * @param {Object} config
423 * @return {Object} - converted config
424 */
425 const configConverter = config => ({
426 use: config.use ?? 'Leaflet',
427 width: '100%',
428 ...config,
429 aliases: {
430 ...defaultAliases,
431 ...(config.aliases ?? {}),
432 },
433 stepCallback: updateAttributeByStep,
434 })
435
436 /** Get render method by converter */
437 const render = renderWith(configConverter)
438 467
439 /** Render each taget element for maps */ 468 /** Render each taget element for maps */
440 let order = 0 469 let order = 0
441 elementsWithMapConfig.forEach(target => { 470 elementsWithMapConfig.forEach(target => {
442 // Get text in code block starts with markdown text '```map' 471 // Get text in code block starts with markdown text '```map'
443 const configText = target 472 const configText = target
444 .querySelector('.language-map')
445 .textContent // BE CAREFUL!!! 0xa0 char is "non-breaking spaces" in HTML text content 473 .textContent // BE CAREFUL!!! 0xa0 char is "non-breaking spaces" in HTML text content
446 // replace it by normal space 474 // replace it by normal space
447 .replace(/\u00A0/g, '\u0020') 475 .replace(/\u00A0/g, '\u0020')
448 476
449 let configList = [] 477 let configList = []
450 try { 478 try {
451 configList = parseConfigsFromYaml(configText).map(assignMapId) 479 configList = mapclay.parseConfigsFromYaml(configText).map(assignMapId)
452 } catch (_) { 480 } catch (_) {
453 console.warn('Fail to parse yaml config for element', target) 481 console.warn('Fail to parse yaml config for element', target)
454 return 482 return