dxf-viewer
Advanced tools
Comparing version 1.0.20 to 1.0.21
{ | ||
"name": "dxf-viewer", | ||
"version": "1.0.20", | ||
"version": "1.0.21", | ||
"description": "JavaScript DXF file viewer", | ||
@@ -24,7 +24,7 @@ "main": "src/index.js", | ||
"dependencies": { | ||
"@types/three": "^0.144.0", | ||
"three": "^0.149.0", | ||
"loglevel": "^1.8.0", | ||
"@types/three": "^0.149.0", | ||
"three": "^0.150.1", | ||
"loglevel": "^1.8.1", | ||
"opentype.js": "^1.3.4" | ||
} | ||
} |
@@ -61,3 +61,4 @@ # DXF viewer | ||
* Block instancing in a grid. Grid attributes are ignored now. | ||
* Dimensions | ||
* Dimensions-specific features and styles (various pre-defined arrowhead blocks, text positioning | ||
tuning, limits and tolerances). Dimensions types other than linear ones. | ||
* Leaders | ||
@@ -72,1 +73,14 @@ * Non-UTF-8 file encoding support. Currently, such files are displayed incorrectly. `$DWGCODEPAGE` | ||
![samples](https://user-images.githubusercontent.com/6065976/143092164-cced2f5f-1af3-42a4-9a71-5dba68df06e7.png) | ||
## Contributing | ||
Please refer to the [contribution guidelines](CONTRIBUTING.md) for details on how to make pull | ||
requests (PRs). The project also requires various example files for testing purposes. If you | ||
encounter any issues with DXF rendering, it would be greatly appreciated if you could provide an | ||
example file that demonstrates the problem by attaching it to a created issue. Creating minimal | ||
examples in CAD software can also be very helpful. Additionally, creating examples in various | ||
proprietary CAD software to which I do not have access would be highly valuable. Due to quite high | ||
entrance level to start coding in this project, it is often more useful to get detailed issue report | ||
with sample files than a pull-request. Since the entrance level to start coding in this project is | ||
quite high, it is often more useful to receive a detailed issue report with sample files rather than | ||
a pull request. |
@@ -107,2 +107,9 @@ import * as three from "three" | ||
/** | ||
* @returns {three.WebGLRenderer | null} Returns the created Three.js renderer. | ||
*/ | ||
GetRenderer(){ | ||
return this.renderer; | ||
} | ||
GetCanvas() { | ||
@@ -173,3 +180,3 @@ return this.canvas | ||
for (const layer of scene.layers) { | ||
this.layers.set(layer.name, new Layer(layer.name, layer.color)) | ||
this.layers.set(layer.name, new Layer(layer.name, layer.displayName, layer.color)) | ||
} | ||
@@ -232,3 +239,7 @@ | ||
for (const lyr of this.layers.values()) { | ||
result.push({name: lyr.name, color: this._TransformColor(lyr.color)}) | ||
result.push({ | ||
name: lyr.name, | ||
displayName: lyr.displayName, | ||
color: this._TransformColor(lyr.color) | ||
}) | ||
} | ||
@@ -887,4 +898,5 @@ return result | ||
class Layer { | ||
constructor(name, color) { | ||
constructor(name, displayName, color) { | ||
this.name = name | ||
this.displayName = displayName | ||
this.color = color | ||
@@ -891,0 +903,0 @@ this.objects = [] |
@@ -41,2 +41,3 @@ /** See TextRenderer.DefaultOptions for default values and documentation. */ | ||
name: string, | ||
displayName: string, | ||
color: number | ||
@@ -50,16 +51,17 @@ } | ||
constructor(domContainer: HTMLElement, options: DxfViewerOptions | null) | ||
HasRenderer(): boolean | ||
GetCanvas(): HTMLCanvasElement | ||
SetSize(width: number, height: number): void | ||
Load(params: DxfViewerLoadParams): Promise<void> | ||
Render(): void | ||
GetLayers(): Iterable<LayerInfo> | ||
ShowLayer(name: string, show: boolean): void | ||
Clear(): void | ||
Destroy(): void | ||
SetView(center: THREE.Vector3, width: number): void | ||
FitView(minX: number, maxX: number, minY: number, maxY: number, padding: number): void | ||
GetScene(): THREE.Scene | ||
GetCamera(): THREE.Camera | ||
GetCanvas(): HTMLCanvasElement | ||
GetLayers(): Iterable<LayerInfo> | ||
GetOrigin(): THREE.Vector2 | ||
GetRenderer(): THREE.WebGLRenderer | null | ||
GetScene(): THREE.Scene | ||
HasRenderer(): boolean | ||
Load(params: DxfViewerLoadParams): Promise<void> | ||
Render(): void | ||
SetSize(width: number, height: number): void | ||
SetView(center: THREE.Vector3, width: number): void | ||
ShowLayer(name: string, show: boolean): void | ||
Subscribe(eventName: EventName, eventHandler: (event: any) => void): void | ||
@@ -66,0 +68,0 @@ Unsubscribe(eventName: EventName, eventHandler: (event: any) => void): void |
@@ -19,2 +19,3 @@ import DxfArrayScanner from './DxfArrayScanner'; | ||
import Text from './entities/text'; | ||
import dimStyleCodes from './DimStyleCodes'; | ||
//import Vertex from './entities/'; | ||
@@ -70,3 +71,3 @@ | ||
}else { | ||
console.error('Cannot read dxf source of type `' + typeof(source)); | ||
console.error('Cannot read DXF source of type `' + typeof(source)); | ||
return null; | ||
@@ -92,3 +93,3 @@ } | ||
var dxf = self._parse(dxfString); | ||
}catch(err) { | ||
} catch(err) { | ||
return done(err); | ||
@@ -109,3 +110,5 @@ } | ||
scanner = new DxfArrayScanner(dxfLinesArray); | ||
if(!scanner.hasNext()) throw Error('Empty file'); | ||
if (!scanner.hasNext()) { | ||
throw Error('Empty file'); | ||
} | ||
@@ -388,3 +391,5 @@ var self = this; | ||
} | ||
if(expectedCount !== actualCount) log.warn('Parsed ' + actualCount + ' ' + tableDefinition.dxfSymbolName + '\'s but expected ' + expectedCount); | ||
if(expectedCount !== actualCount) { | ||
log.warn(`Parsed ${actualCount} ${tableDefinition.dxfSymbolName}'s but expected ${expectedCount}`); | ||
} | ||
} | ||
@@ -566,3 +571,5 @@ curr = scanner.next(); | ||
log.debug('}'); | ||
if(length > 0 && length !== ltype.pattern.length) log.warn('lengths do not match on LTYPE pattern'); | ||
if (length > 0 && length !== ltype.pattern.length) { | ||
log.warn('lengths do not match on LTYPE pattern'); | ||
} | ||
ltypes[ltypeName] = ltype; | ||
@@ -638,2 +645,47 @@ ltype = {}; | ||
var parseDimStyles = function() { | ||
var dimStyles = {}, | ||
styleName, | ||
style = {}; | ||
log.debug('DimStyle {'); | ||
curr = scanner.next(); | ||
while(!groupIs(0, 'ENDTAB')) { | ||
if (dimStyleCodes.has(curr.code)) { | ||
style[dimStyleCodes.get(curr.code)] = curr.value | ||
curr = scanner.next(); | ||
} else { | ||
switch(curr.code) { | ||
case 2: // style name | ||
style.name = curr.value; | ||
styleName = curr.value; | ||
curr = scanner.next(); | ||
break; | ||
case 0: | ||
// New style | ||
if(curr.value === 'DIMSTYLE') { | ||
log.debug('}'); | ||
dimStyles[styleName] = style; | ||
log.debug('DimStyle {'); | ||
style = {}; | ||
styleName = undefined; | ||
curr = scanner.next(); | ||
} | ||
break; | ||
default: | ||
logUnhandledGroup(curr); | ||
curr = scanner.next(); | ||
break; | ||
} | ||
} | ||
} | ||
// Note: do not call scanner.next() here, | ||
// parseLayerTable() needs the current group | ||
log.debug('}'); | ||
dimStyles[styleName] = style; | ||
return dimStyles; | ||
}; | ||
var tableDefinitions = { | ||
@@ -657,2 +709,8 @@ VPORT: { | ||
parseTableRecords: parseLayers | ||
}, | ||
DIMSTYLE: { | ||
tableRecordsProperty: 'dimStyles', | ||
tableName: 'dimstyle', | ||
dxfSymbolName: 'DIMSTYLE', | ||
parseTableRecords: parseDimStyles | ||
} | ||
@@ -683,3 +741,3 @@ }; | ||
var handler = self._entityHandlers[curr.value]; | ||
if(handler != null) { | ||
if (handler != null) { | ||
log.debug(curr.value + ' {'); | ||
@@ -701,3 +759,5 @@ entity = handler.parseEntity(scanner, curr); | ||
} | ||
if(endingOnValue == 'ENDSEC') curr = scanner.next(); // swallow up ENDSEC, but not ENDBLK | ||
if (endingOnValue == 'ENDSEC') { | ||
curr = scanner.next(); // swallow up ENDSEC, but not ENDBLK | ||
} | ||
return entities; | ||
@@ -734,3 +794,3 @@ }; | ||
point.z = curr.value; | ||
return point; | ||
@@ -740,6 +800,10 @@ }; | ||
var ensureHandle = function(entity) { | ||
if(!entity) throw new TypeError('entity cannot be undefined or null'); | ||
if (!entity) { | ||
throw new TypeError('entity cannot be undefined or null'); | ||
} | ||
if(!entity.handle) entity.handle = lastHandle++; | ||
}; | ||
if (!entity.handle) { | ||
entity.handle = lastHandle++; | ||
} | ||
} | ||
@@ -746,0 +810,0 @@ parseAll(); |
@@ -24,3 +24,3 @@ | ||
default: | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -39,3 +39,3 @@ } | ||
var verticesPer3dFace = 4; // there can be up to four vertices per face, although 3 is most used for TIN | ||
for (i = 0; i <= verticesPer3dFace; i++) { | ||
@@ -42,0 +42,0 @@ var vertex = {}; |
@@ -33,3 +33,3 @@ | ||
default: // ignored attribute | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -40,2 +40,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -83,3 +83,3 @@ | ||
default: | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -91,2 +91,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -37,3 +37,3 @@ | ||
default: // ignored attribute | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -44,2 +44,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -19,2 +19,5 @@ | ||
break; | ||
case 3: // Dimension style name | ||
entity.styleName = curr.value; | ||
break; | ||
case 10: // X coordinate of 'first alignment point' | ||
@@ -56,4 +59,9 @@ entity.anchorPoint = helpers.parsePoint(scanner); | ||
break; | ||
case 53: // Rotation angle of the dimension text away from its default orientation (the | ||
//direction of the dimension line) | ||
entity.textRotation = curr.value; | ||
break; | ||
default: // check common entity attributes | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -66,3 +74,1 @@ } | ||
}; | ||
@@ -38,6 +38,6 @@ | ||
default: // check common entity attributes | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
} | ||
curr = scanner.next(); | ||
@@ -47,2 +47,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -50,3 +50,3 @@ | ||
default: // check common entity attributes | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -59,3 +59,1 @@ } | ||
}; | ||
@@ -27,9 +27,9 @@ | ||
default: | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
} | ||
curr = scanner.next(); | ||
} | ||
return entity; | ||
}; | ||
}; |
@@ -39,3 +39,3 @@ | ||
default: | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -101,2 +101,2 @@ } | ||
return vertices; | ||
}; | ||
}; |
@@ -48,3 +48,3 @@ | ||
default: | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -55,2 +55,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -28,3 +28,3 @@ | ||
default: // check common entity attributes | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -36,2 +36,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -53,3 +53,3 @@ | ||
default: | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -88,3 +88,3 @@ } | ||
if (curr.code == 0) break; | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
curr = scanner.next(); | ||
@@ -91,0 +91,0 @@ } |
@@ -33,3 +33,3 @@ | ||
default: // check common entity attributes | ||
helpers.checkCommonEntityProperties(entity, currentGroup); | ||
helpers.checkCommonEntityProperties(entity, currentGroup, scanner); | ||
break; | ||
@@ -41,2 +41,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -63,3 +63,3 @@ | ||
default: | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -71,2 +71,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -41,3 +41,3 @@ | ||
default: // check common entity attributes | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
@@ -48,2 +48,2 @@ } | ||
return entity; | ||
}; | ||
}; |
@@ -55,9 +55,9 @@ | ||
default: | ||
helpers.checkCommonEntityProperties(entity, curr); | ||
helpers.checkCommonEntityProperties(entity, curr, scanner); | ||
break; | ||
} | ||
curr = scanner.next(); | ||
} | ||
return entity; | ||
}; | ||
}; |
import AUTO_CAD_COLOR_INDEX from './AutoCadColorIndex'; | ||
import ExtendedDataParser from './ExtendedDataParser'; | ||
@@ -14,3 +15,3 @@ /** | ||
* the scanner remains on the last group of the coordinate. | ||
* @param {*} scanner | ||
* @param {*} scanner | ||
*/ | ||
@@ -43,3 +44,3 @@ export function parsePoint(scanner) { | ||
point.z = curr.value; | ||
return point; | ||
@@ -69,6 +70,25 @@ } | ||
* was handled by this function. | ||
* @param {*} entity - the entity currently being parsed | ||
* @param {*} entity - the entity currently being parsed | ||
* @param {*} curr - the current group being parsed | ||
*/ | ||
export function checkCommonEntityProperties(entity, curr) { | ||
export function checkCommonEntityProperties(entity, curr, scanner) { | ||
let xdataParser = null | ||
while (curr.code >= 1000) { | ||
if (xdataParser == null) { | ||
xdataParser = new ExtendedDataParser() | ||
} | ||
if (xdataParser.Feed(curr)) { | ||
xdataParser.Finish(entity) | ||
xdataParser = null | ||
} else { | ||
curr = scanner.next() | ||
} | ||
} | ||
if (xdataParser) { | ||
xdataParser.Finish(entity) | ||
/* Groups following XDATA should be parsed on next iteration. */ | ||
scanner.rewind() | ||
return true | ||
} | ||
switch(curr.code) { | ||
@@ -119,11 +139,2 @@ case 0: | ||
break; | ||
case 1000: | ||
entity.extendedData = entity.extendedData || {}; | ||
entity.extendedData.customStrings = entity.extendedData.customStrings || []; | ||
entity.extendedData.customStrings.push(curr.value); | ||
break; | ||
case 1001: | ||
entity.extendedData = entity.extendedData || {}; | ||
entity.extendedData.applicationName = curr.value; | ||
break; | ||
default: | ||
@@ -130,0 +141,0 @@ return false; |
@@ -5,5 +5,45 @@ import {DxfScene, Entity} from "./DxfScene" | ||
import {Matrix3, Vector2} from "three" | ||
import {MTextFormatParser} from "./MTextFormatParser"; | ||
import {MTextFormatParser} from "./MTextFormatParser" | ||
/** Regex for parsing special characters in text entities. */ | ||
const SPECIAL_CHARS_RE = /(?:%%([dpcou%]))|(?:\\U\+([0-9a-fA-F]{4}))/g | ||
/** | ||
* Parse special characters in text entities and convert them to corresponding unicode | ||
* characters. | ||
* https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2019/ENU/AutoCAD-Core/files/GUID-518E1A9D-398C-4A8A-AC32-2D85590CDBE1-htm.html | ||
* @param {string} text Raw string. | ||
* @return {string} String with special characters replaced. | ||
*/ | ||
export function ParseSpecialChars(text) { | ||
return text.replaceAll(SPECIAL_CHARS_RE, (match, p1, p2) => { | ||
if (p1 !== undefined) { | ||
switch (p1) { | ||
case "d": | ||
return "\xb0" | ||
case "p": | ||
return "\xb1" | ||
case "c": | ||
return "\u2205" | ||
case "o": | ||
/* Toggles overscore mode on and off, not implemented. */ | ||
return "" | ||
case "u": | ||
/* Toggles underscore mode on and off, not implemented. */ | ||
return "" | ||
case "%": | ||
return "%" | ||
} | ||
} else if (p2 !== undefined) { | ||
const code = parseInt(p2, 16) | ||
if (isNaN(code)) { | ||
return match | ||
} | ||
return String.fromCharCode(code) | ||
} | ||
return match | ||
}) | ||
} | ||
/** | ||
* Helper class for rendering text. | ||
@@ -94,2 +134,18 @@ * Currently it is just basic very simplified implementation for MVP. Further work should include: | ||
/** Get width in model space units for a single line of text. | ||
* @param text {string} | ||
* @param fontSize {number} | ||
*/ | ||
GetLineWidth(text, fontSize) { | ||
const block = new TextBlock(fontSize) | ||
for (const char of text) { | ||
const shape = this._GetCharShape(char) | ||
if (!shape) { | ||
continue | ||
} | ||
block.PushChar(char, shape) | ||
} | ||
return block.GetCurrentPosition() | ||
} | ||
/** | ||
@@ -337,3 +393,3 @@ * @param text {string} | ||
/** TEXT group attribute 72 values. */ | ||
const HAlign = Object.freeze({ | ||
export const HAlign = Object.freeze({ | ||
LEFT: 0, | ||
@@ -348,3 +404,3 @@ CENTER: 1, | ||
/** TEXT group attribute 73 values. */ | ||
const VAlign = Object.freeze({ | ||
export const VAlign = Object.freeze({ | ||
BASELINE: 0, | ||
@@ -983,2 +1039,2 @@ BOTTOM: 1, | ||
} | ||
} | ||
} |
Sorry, the diff of this file is too big to display
313485
42
8174
85
+ Added@types/three@0.149.0(transitive)
+ Addedthree@0.150.1(transitive)
- Removed@types/three@0.144.0(transitive)
- Removedthree@0.149.0(transitive)
Updated@types/three@^0.149.0
Updatedloglevel@^1.8.1
Updatedthree@^0.150.1