odraw-symbols
v1.0.1
Published
Comprehensive orienteering map symbol library supporting ISOM, ISSkiOM, ISMTBOM, and Course Design standards
Maintainers
Readme
@odraw/symbols
Comprehensive orienteering map symbol library for JavaScript/TypeScript
A complete, type-safe library of orienteering map symbols supporting ISOM, ISSkiOM, ISMTBOM, ISSprOM, ISSOM, and Course Design standards. Perfect for building orienteering mapping tools, course planning applications, and map visualization software.
Features
- ✅ Complete Symbol Coverage - All ISOM 2017-2 symbols plus specialized standards
- ✅ Multiple Standards - ISOM, ISSkiOM, ISMTBOM, ISSprOM, ISSOM, Course Design
- ✅ Multiple Scales - Support for 1:4000, 1:5000, 1:7500, 1:10000, 1:12500, 1:15000, 1:20000
- ✅ Actual SVG Geometry - Extracts real symbol shapes from .omap files
- ✅ Individual SVG Files - Each symbol exported as standalone SVG with metadata
- ✅ Type-Safe - Full TypeScript support with comprehensive type definitions
- ✅ Smart Categorization - Symbols organized by category (Landforms, Water, Vegetation, etc.)
- ✅ Flexible Filtering - Filter by standard, category, scale, code, or search text
- ✅ Rich Metadata - Includes code, name, description, colors, and more
- ✅ Zero Dependencies - Lightweight and fast (runtime has no dependencies)
- ✅ Tree-Shakeable - Only import what you need
Installation
npm install @odraw/symbolsQuick Start
import symbols from '@odraw/symbols';
// Get all symbols
const allSymbols = symbols.getAllSymbols();
// Get symbols by standard
const isomSymbols = symbols.getSymbolsByStandard('ISOM');
// Get symbols by category
const courseSymbols = symbols.getSymbolsByCategory('course');
// Get a specific symbol
const startSymbol = symbols.getSymbol('701', 'ISOM', 15000);
// Search symbols
const results = symbols.search('control');Usage Examples
1. Load Symbols by Standard
import { getSymbolsByStandard, getAvailableStandards } from '@odraw/symbols';
// Get all available standards
const standards = getAvailableStandards();
// ['ISOM', 'ISSkiOM', 'ISMTBOM', 'ISSprOM', 'ISSOM', 'CourseDesign']
// Get ISOM symbols
const isomSymbols = getSymbolsByStandard('ISOM');
// Get ISSkiOM symbols
const skiSymbols = getSymbolsByStandard('ISSkiOM');2. Browse Symbols by Category
import { getSymbolsGroupedByCategory, getAllCategories } from '@odraw/symbols';
// Get all categories with info
const categories = getAllCategories();
// Returns: [{ id, name, description, codeRange, color, icon }, ...]
// Get symbols grouped by category
const grouped = getSymbolsGroupedByCategory({ standard: 'ISOM', scale: 15000 });
grouped.forEach((symbols, category) => {
console.log(`${category}: ${symbols.length} symbols`);
symbols.forEach(symbol => {
console.log(` ${symbol.code} - ${symbol.name}`);
});
});3. Display Symbol Information
import { getSymbolsByCode } from '@odraw/symbols';
// Get all variations of symbol 701 (Start)
const startSymbols = getSymbolsByCode('701');
startSymbols.forEach(symbol => {
console.log(`Code: ${symbol.code}`);
console.log(`Name: ${symbol.name}`);
console.log(`Description: ${symbol.description}`);
console.log(`Standard: ${symbol.standard}`);
console.log(`Scale: 1:${symbol.scale}`);
console.log(`Category: ${symbol.category}`);
console.log(`Color: ${symbol.color.hex}`);
console.log(`SVG: ${symbol.svg ? 'Available' : 'Not available'}`);
});4. Use SVG Symbols
import { getSymbol } from '@odraw/symbols';
// Get a symbol with SVG geometry
const controlSymbol = getSymbol('702', 'CourseDesign', 10000);
if (controlSymbol?.svg) {
// Use the SVG directly in your HTML
document.getElementById('symbol-container').innerHTML = controlSymbol.svg;
// Or create an image element
const img = document.createElement('img');
img.src = `data:image/svg+xml;base64,${btoa(controlSymbol.svg)}`;
// SVG includes metadata as data attributes
console.log('Symbol metadata embedded in SVG');
}
// Load individual SVG files (if exported)
const svgUrl = `./symbols/svg/CourseDesign_10000_702.svg`;
const svgContent = await fetch(svgUrl).then(r => r.text());5. Filter Symbols
import { filterSymbols } from '@odraw/symbols';
// Complex filtering
const filtered = filterSymbols({
standard: ['ISOM', 'ISSprOM'],
category: ['course', 'landforms'],
scale: [15000, 10000],
search: 'control'
});
// Filter by code prefix
const landformSymbols = filterSymbols({
standard: 'ISOM',
code: ['101', '102', '103', '104', '105']
});6. Build a Symbol Picker
import {
getSymbolsGroupedByCategory,
getCategoryInfo,
type Symbol
} from '@odraw/symbols';
function SymbolPicker({ standard = 'ISOM', scale = 15000 }) {
const grouped = getSymbolsGroupedByCategory({ standard, scale });
return (
<div className="symbol-picker">
{Array.from(grouped.entries()).map(([category, symbols]) => {
const info = getCategoryInfo(category);
return (
<div key={category} className="category">
<h3 style={{ color: info.color }}>
{info.icon} {info.name}
</h3>
<div className="symbols">
{symbols.map(symbol => (
<div
key={symbol.id}
className="symbol"
title={`${symbol.code}: ${symbol.name}\n${symbol.description}`}
onClick={() => onSymbolSelect(symbol)}
>
<div className="icon">
{symbol.svg ? (
<div
dangerouslySetInnerHTML={{ __html: symbol.svg }}
style={{ width: '24px', height: '24px' }}
/>
) : (
<div
className="placeholder"
style={{ backgroundColor: symbol.color.hex }}
>
{symbol.code}
</div>
)}
</div>
<span>{symbol.name}</span>
</div>
))}
</div>
</div>
);
})}
</div>
);
}7. Search Functionality
import { search } from '@odraw/symbols';
// Search in name, description, and code
const results = search('boulder');
results.forEach(symbol => {
console.log(`${symbol.code} - ${symbol.name} (${symbol.standard})`);
});8. Get Statistics
import { getStatistics } from '@odraw/symbols';
const stats = getStatistics();
console.log(`Total Symbols: ${stats.totalSymbols}`);
console.log(`Symbol Sets: ${stats.totalSymbolSets}`);
console.log(`Standards: ${stats.standards.join(', ')}`);
console.log(`Scales: ${stats.scales.map(s => `1:${s}`).join(', ')}`);
stats.categories.forEach(cat => {
console.log(`${cat.name}: ${cat.count} symbols`);
});API Reference
Main Functions
getAllSymbols()- Get all symbolsgetSymbolById(id)- Get symbol by unique IDgetSymbolsByCode(code)- Get all symbols with a specific codegetSymbol(code, standard, scale)- Get a specific symbolfilterSymbols(filter)- Filter symbols by criteriagetSymbolsByStandard(standard)- Get symbols by standardgetSymbolsByCategory(category)- Get symbols by categorygetSymbolsByScale(scale)- Get symbols by scalegetSymbolsGroupedByCategory(filter?)- Get symbols grouped by categorygetSymbolsGroupedByCodePrefix(filter?)- Get symbols grouped by code prefixsearch(query)- Search symbolsgetStatistics()- Get library statistics
Types
type SymbolStandard = 'ISOM' | 'ISSkiOM' | 'ISMTBOM' | 'ISSprOM' | 'ISSOM' | 'CourseDesign';
type SymbolCategory =
| 'landforms'
| 'rock-boulders'
| 'water'
| 'vegetation-white'
| 'vegetation-green'
| 'vegetation-boundaries'
| 'man-made'
| 'technical'
| 'course';
interface Symbol {
id: string;
code: string;
name: string;
description: string;
standard: SymbolStandard;
category: SymbolCategory;
type: 'point' | 'line' | 'area' | 'text' | 'combined';
color: MapColor;
scale: number;
// ... more properties
}Symbol Categories
| Category | Code Range | Description | Color | |----------|------------|-------------|-------| | Landforms | 101-117 | Contours, cliffs, earth banks | Brown | | Rock & Boulders | 201-213 | Cliffs, boulders, rocky areas | Black | | Water | 301-320 | Lakes, streams, marshes | Blue | | Vegetation (Open) | 401-419 | Open land, cultivation | Yellow | | Vegetation (Forest) | 501-524 | Forest, undergrowth | Green | | Vegetation Boundaries | 525-529 | Vegetation edges | Dark Green | | Man-made | 501-529 | Roads, buildings, fences | Black | | Technical | 801-899 | North lines, scales | Gray | | Course | 701-799 | Start, controls, finish | Purple |
Supported Standards
- ISOM 2017-2 - International Specification for Orienteering Maps
- ISSkiOM 2019 - International Specification for Ski Orienteering Maps
- ISMTBOM - International Specification for Mountain Bike Orienteering Maps
- ISSprOM 2019 - International Specification for Sprint Orienteering Maps
- ISSOM - International Specification for Sport Orienteering Maps
- Course Design - IOF Course Setting symbols
Supported Scales
- 1:4000
- 1:5000
- 1:7500
- 1:10000
- 1:12500
- 1:15000
- 1:20000
SVG Rendering Status
The library extracts actual symbol geometry from .omap XML files and converts them to SVG format.
Currently Supported
- ✅ Point symbols (circles, basic shapes)
- ✅ Line symbols with proper colors and widths
- ✅ Area symbols with fills
- ✅ Text symbols with icon text
- ✅ Basic coordinate parsing and scaling
- ✅ Color extraction from .omap definitions
Complex Features (Simplified)
- ⚠️ Multi-element symbols with start/mid/end patterns
- ⚠️ Nested symbol definitions
- ⚠️ Symbol patterns and advanced fills
- ⚠️ Rotatable symbols with proper orientation
- ⚠️ Dash patterns and line decorations
- ⚠️ Curved paths and bezier curves
Recommendations
- For most use cases: The automated SVG extraction works well
- For critical symbols: Consider manually exporting from OpenOrienteering Mapper
- For production: Use the hybrid approach (automated + manual for key symbols)
SVG Symbol Extraction
The library now automatically extracts SVG geometry from .omap files and exports individual SVG files for each symbol. This provides actual symbol renderings instead of placeholder icons.
Automated SVG Export
Export all 3,016+ symbols as individual SVG files:
# Export all symbols to SVG files
npm run export:svg
# This creates files like:
# symbols/svg/ISOM_15000_101.svg
# symbols/svg/CourseDesign_10000_702.svg
# etc.Each SVG file includes:
- Actual symbol geometry extracted from .omap files
- Complete metadata as data attributes
- Accessibility features (title, description)
- Proper scaling and viewBox
SVG Export Options
Option 1: Automated Export (Current)
- ✅ Fast - exports all symbols in seconds
- ✅ Includes complete metadata
- ✅ Reproducible and automated
- ⚠️ Simplified rendering for complex symbols
Option 2: Manual Export from OpenOrienteering Mapper
- ✅ Most accurate rendering
- ✅ Handles all symbol complexities
- ❌ Very time-consuming (3,016+ symbols)
- ❌ Manual process
Option 3: Hybrid Approach (Recommended)
- Use automated export for all symbols
- Manually export critical symbols from Mapper
- Replace auto-generated with manual for important symbols
Using Exported SVGs
// SVG files include metadata
const svgContent = await fetch('./symbols/svg/ISOM_15000_101.svg').then(r => r.text());
// Metadata is embedded in the SVG element:
// <svg data-code="101" data-name="Contour" data-standard="ISOM" ...>Development
# Install dependencies
npm install
# Parse symbol files and extract SVG
npm run build:symbols
# Export symbols as individual SVG files
npm run export:svg
# Build library
npm run build
# Run tests
npm test
# Development mode
npm run devSVG Export Scripts
The library includes several scripts for working with SVG symbols:
scripts/export-symbols-svg.ts- Automated SVG export from .omap filesscripts/export-svg-guide.md- Guide for different SVG export approachesscripts/mapper-export-guide.md- Manual export using OpenOrienteering Mapper
For detailed information about SVG extraction methods, see the guides in the scripts/ directory.
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Credits
Symbol definitions are based on the International Orienteering Federation (IOF) specifications and OpenOrienteering Mapper project.
