/** * 画个标 · 装饰图形系统 * 落地 GitHub logo-design-skill 专业设计方法论:专业 LOGO 的"设计感"来自 * 图形层次 —— 双线环、点状环绕、星点、角括号、弧线、绶带、几何衬底(容器)。 * 所有装饰原语为 24x24 viewBox 字符串,作为 icon 元素渲染。 * fill=true 表示实心填充型(无描边,可用于容器/色块);fill=false 表示描边型。 */ const HGB_Decorations = (function () { 'use strict'; let seq = 0; function uid() { return 'dc' + Date.now().toString(36) + (seq++).toString(36); } /** 颜色亮化:amt 0~1(值越大越接近白色) */ function lighten(hex, amt) { const c = String(hex || '#888888').replace('#', ''); if (c.length !== 6) return '#cccccc'; const f = (v) => Math.round(v + (255 - v) * Math.min(1, Math.max(0, amt))).toString(16).padStart(2, '0'); return '#' + f(parseInt(c.slice(0, 2), 16)) + f(parseInt(c.slice(2, 4), 16)) + f(parseInt(c.slice(4, 6), 16)); } /** 颜色加深:amt 0~1 */ function shade(hex, amt) { const c = String(hex || '#888888').replace('#', ''); if (c.length !== 6) return '#444444'; const f = (v) => Math.round(v * (1 - Math.min(1, Math.max(0, amt)))).toString(16).padStart(2, '0'); return '#' + f(parseInt(c.slice(0, 2), 16)) + f(parseInt(c.slice(2, 4), 16)) + f(parseInt(c.slice(4, 6), 16)); } /** 判断颜色明暗(返回 true 表示偏深色) */ function isDark(hex) { const c = String(hex || '#FFFFFF').replace('#', ''); if (c.length !== 6) return false; const r = parseInt(c.slice(0, 2), 16), g = parseInt(c.slice(2, 4), 16), b = parseInt(c.slice(4, 6), 16); return (0.2126 * r + 0.7152 * g + 0.0722 * b) < 150; } /** * 装饰原语库 */ const DECO_KIT = { /* ---- 环绕/边框类(描边型) ---- */ 'deco-dotring': { name: '点状环绕', fill: true, sw: 0, opacity: 0.9, svg: '' }, 'deco-rayring': { name: '射线环', fill: false, sw: 2, opacity: 0.95, svg: (function () { let p = ''; for (let i = 0; i < 12; i++) { const a = i * 30 * Math.PI / 180, c = Math.cos(a), s = Math.sin(a); p += 'M' + (12 + 8 * c).toFixed(2) + ' ' + (12 + 8 * s).toFixed(2) + 'L' + (12 + 11.5 * c).toFixed(2) + ' ' + (12 + 11.5 * s).toFixed(2); } return p; })() }, 'deco-doublering': { name: '双线环', fill: false, sw: 4, opacity: 0.85, svg: '' }, 'deco-arc-top': { name: '上弧形', fill: false, sw: 5, opacity: 0.9, svg: '' }, 'deco-arc-bottom': { name: '下弧形', fill: false, sw: 5, opacity: 0.9, svg: '' }, 'deco-corner-tl': { name: '左上角括号', fill: false, sw: 5, opacity: 0.95, svg: '' }, 'deco-corner-br': { name: '右下角括号', fill: false, sw: 5, opacity: 0.95, svg: '' }, 'deco-stars': { name: '星点散落', fill: true, sw: 0, opacity: 0.9, svg: '' }, 'deco-divider': { name: '菱形分隔线', fill: true, sw: 0, opacity: 0.95, svg: '' }, 'deco-chevron': { name: '人字饰带', fill: false, sw: 5, opacity: 0.9, svg: '' }, 'deco-tri-corner': { name: '三角角标', fill: true, sw: 0, opacity: 0.9, svg: '' }, 'deco-line': { name: '细分隔线', fill: true, sw: 0, opacity: 0.9, svg: '' }, 'deco-spark': { name: '光芒四射', fill: true, sw: 0, opacity: 0.9, svg: '' }, 'deco-laurel-l': { name: '左月桂叶', fill: false, sw: 5, opacity: 0.9, svg: '' }, 'deco-laurel-r': { name: '右月桂叶', fill: false, sw: 5, opacity: 0.9, svg: '' }, /* ---- 实心几何衬底(容器,图标徽章化) ---- */ 'deco-shape-circle': { name: '圆形衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-squircle':{ name: '圆角方形衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-hexagon': { name: '六边形衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-star': { name: '星形衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-shield': { name: '盾形衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-diamond': { name: '菱形衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-triangle': { name: '三角衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-arch': { name: '拱形衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-pill': { name: '胶囊衬底', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-ribbon': { name: '绶带横幅', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-shape-heart': { name: '爱心衬底', fill: true, sw: 0, opacity: 1, svg: '' }, /* ---- 分屏/背景面板(填充型,铺满画布) ---- */ 'deco-panel-left': { name: '左半色板', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-panel-diag': { name: '对角色板', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-panel-band': { name: '横向色带', fill: true, sw: 0, opacity: 1, svg: '' }, 'deco-panel-barc': { name: '底边色块', fill: true, sw: 0, opacity: 1, svg: '' } }; /** * 构造装饰元素(同 icon 元素结构,渲染走 applyIconStyle) * @param {string} id DECO_KIT 键名 * @param {number} x 左上角 x * @param {number} y 左上角 y * @param {number} w 宽 * @param {number} h 高 * @param {string} color 填充/描边色 * @param {object} grad {id,type,from,to} 渐变对象(有则覆盖纯色) */ function decoEl(id, x, y, w, h, color, grad) { const def = DECO_KIT[id]; if (!def) return null; const fill = grad ? 'url(#' + grad.id + ')' : (def.fill ? color : 'none'); return { id: uid(), type: 'icon', name: def.name, iconId: id, svg: def.svg, x, y, w, h, rotation: 0, fill: fill, stroke: def.fill ? 'none' : color, strokeWidth: def.sw || 4, grad: grad || null, opacity: def.opacity != null ? def.opacity : 1, visible: true, locked: false }; } /** * 按风格返回装饰组合(供布局选择参考;布局也可自选具体原语) * @param {string} styleId 风格 id * @param {object} palette 配色 {colors:[主,辅,点,背景]} * @returns {{dec:Array, decoColor:string, grad:object}} */ function buildDecoSet(styleId, palette) { const colors = (palette && palette.colors) || ['#2563EB', '#3B82F6', '#F59E0B', '#FFFFFF']; const decoColor = lighten(colors[1] || colors[0], 0.42); // 浅色点缀,低对比 const grad = { id: 'grad-main' + (++seq), type: 'linear', from: colors[0], to: lighten(colors[0], 0.28) }; const map = { minimal: ['deco-doublering'], gradient: ['deco-dotring'], vintage: ['deco-arc-top', 'deco-arc-bottom'], tech: ['deco-corner-tl', 'deco-corner-br'], playful: ['deco-stars'], luxury: ['deco-divider'], flat: ['deco-shape-circle'] }; return { dec: map[styleId] || [], decoColor, grad }; } return { decoEl, buildDecoSet, lighten, shade, isDark, DECO_KIT }; })();